Java Object Layout – czyli jak sprawdzić rozmiar obiektów w pamięci
Java Object Layout – czyli jak sprawdzić rozmiar obiektów w pamięci
Java Object Layout to biblioteka która umożliwia sprawdzenie ile miejsca w pamięci zajmuje utworzony obiekt:
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency>
Zanim zaczniemy weryfikować ile pamięci zajmują obiekty w Javie to należy doprecyzować pewne kwestie. Programy napisane w Javie mogą być uruchomione na dowolnej platformie. Z tego też powodu wirtualna maszyna Javy posiada predefiniowane rozmiary dla typów prymitywnych:
byte | 1 byte | Stores whole numbers from -128 to 127 |
short | 2 bytes | Stores whole numbers from -32,768 to 32,767 |
int | 4 bytes | Stores whole numbers from -2,147,483,648 to 2,147,483,647 |
long | 8 bytes | Stores whole numbers from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
float | 4 bytes | Stores fractional numbers. Sufficient for storing 6 to 7 decimal digits |
double | 8 bytes | Stores fractional numbers. Sufficient for storing 15 decimal digits |
boolean | 1 bit | Stores true or false values |
char | 2 bytes | Stores a single character/letter or ASCII values |
Każdy typ złożony przechowuje informacje o samym sobie tzw. metadane:
class (4 bajty) – wskaźnik do typu klasy np. dla obiektu java.lang.Integer jest to wskaźnik do klasy java.lang.Integer,
flagi (4 bajty) – informacja czy zdefiniowany typ to klasa czy tablica oraz informacja o hashCode,
lock (4 bajty) – monitor czyli informacja czy dostęp do obiektu jest synchronizowany,
size (4 bajty) – rozmiar tablicy – występuje tylko i wyłącznie dla tablic.
Dla klasy java.lang.Integer i 32 bitowego JVMa informacje te można przedstawić następująco:
Zdefiniujmy dla przykładu prostą klasę Shortcut:
public class Shortcut { int shortcut; public static void main(String[] args) { System.out.println(VM.current().details()); } }
po uruchomieniu programu w wyniku otrzymamy informacje o użytej wersji maszyny wirtualnej:
# Running 64-bit HotSpot VM. # Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
wyświetlmy teraz informacje o rozmiarze utworzonego obiektu klasy Shortcut:
System.out.println(ClassLayout.parseClass(Shortcut.class).toPrintable(new Shortcut()));
wynik:
Shortcut object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315) 12 4 int Shortcut.shortcut 0 Instance size: 16 bytes
otrzymujemy 16 bajtów – (4 bajty zmienna shortcut, 12 bajtów metadane klasy). Dodajmy teraz zmienną shortcutDescription:
public class Shortcut { int shortcut; String shortcutDescription; public static void main(String[] args) { System.out.println(VM.current().details()); System.out.println(ClassLayout.parseClass(Shortcut.class).toPrintable(new Shortcut())); } }
wynik to 24 bajty a nie jak można było się spodziewać 20 (referencja do obiektu klasy String zajmuje 4 bajty)!
Shortcut object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315) 12 4 int Shortcut.shortcut 0 16 4 java.lang.String Shortcut.shortcutDescription null 20 4 (loss due to the next object alignment) Instance size: 24 bytes
Dlaczego jest taka różnica? Wynika to z tego, że wystąpiło wyrównanie do 8 bajtów. Najbliższej 20 jest liczba 24 biorąc pod uwagę wielokrotność liczby 8. Wadą klasy ClassLayout jest to, że nie zlicza ona rozmiaru dla typów zagnieżdżonych. Problem ten rozwiązać można z użyciem klasy GraphLayout.
Leave a comment