2013-03-19 8 views
8

Próbuję zrozumieć, jaki jest ślad pamięci obiektu w Javie. Czytam this i inne dokumenty dotyczące obiektu i pamięci w Javie.Objawy pamięci obiektów Java - Visualvm i java.sizeOf pomiar

Jednak kiedy używam VisualVM sizeof Java library lub, mam dwa różne wyniki, gdzie żaden z nich nogi, co mogę oczekiwać według poprzedniego odniesienia (http://www.javamex.com).

Dla mojego testu używam Java SE 7 Developer Preview na 64-bits Mac z java.sizeof 0.2.1 i visualvm 1.3.5.

Mam trzy klasy, TestObject, TestObject2, TestObject3.

public class TestObject 
{ 

} 

public class TestObject2 extends TestObject 
{ 
    int a = 3; 
} 

public class TestObject3 extends TestObject2 
{ 
    int b = 4; 
    int c = 5; 
} 

Moje główne klasy:

public class memoryTester 
{ 
    public static void main(String[] args) throws Throwable 
    { 
     TestObject object1 = new TestObject(); 
     TestObject2 object2 = new TestObject2(); 
     TestObject3 object3 = new TestObject3(); 

     int sum = object2.a + object3.b + object3.c; 
     System.out.println(sum); 

     SizeOf.turnOnDebug(); 

     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object1))); 
     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object2))); 
     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object3))); 
    } 
} 

Z java.SizeOf() uzyskać:

{ test.TestObject 
} size = 16.0b 
16.0b 

{ test.TestObject2 
a = 3 
} size = 16.0b 
16.0b 

{ test.TestObject3 
b = 4 
c = 5 
} size = 24.0b 
24.0b 

Z VisualVM mam:

this (Java frame) TestObject #1 16 
this (Java frame) TestObject2 #1 20 
this (Java frame) TestObject3 #1 28 

Według dokumentacji ja czytaj przez Internet, ponieważ jestem w 64-bitach, powinienem mają nagłówek obiektu 16 bajtów, ok dla TestObject.

Następnie dla TestObject2 powinienem dodać 4 bajty dla pola liczby całkowitej dając 20 bajtów, powinienem dodać jeszcze 4 bajty dopełnienia, dając całkowity rozmiar 24 bajtów dla TestObject2. Czy się mylę?

Kontynuując w ten sposób dla TestObject3, muszę dodać 8 bajtów więcej dla dwóch pól liczb całkowitych, które powinny dać 32 bajty.

VisualVm wydaje się ignorować dopełnienie, podczas gdy java.sizeOf wydaje się brakować 4 bajtów, tak jakby były zawarte w nagłówku obiektu. Mogę zastąpić liczbę całkowitą przez 4 wartości logiczne, co daje taki sam wynik.

Pytania:

Dlaczego te dwa narzędzia dają różne wyniki?

Czy mamy dopełnienie?

Czytałem również gdzieś (nie znalazłem linku), że między klasą a jej podklasą może być trochę dopełnienia, czy to prawda? W takim przypadku odziedziczone drzewo klas może mieć trochę pamięci narzutowej?

Wreszcie, czy jest jakiś specyfikacja/specyfikacja Java, która opisuje, co robi Java?

Dzięki za pomoc.

Aktualizacja:

Aby odpowiedzieć na komentarz z utapyngo, aby uzyskać rozmiaru obiektów w VisualVM, tworzę heapdump, a następnie w „klas” część I sprawdź kolumnę „rozmiar” następny po kolumna "instances". Liczba wystąpień 1 dla każdego rodzaju obiektów.

Aby odpowiedzieć na komentarz Nathaniela Forda, zainicjalizowałem każdą z nich, a następnie zrobiłem z nimi prostą sumę w mojej metodzie głównej, aby z nich skorzystać. To nie zmieniło wyników.

+0

Mamy nie wiedział co jest w porządku, czy też, nie widząc ich logikę na sposób ich pomiaru zużycia pamięci. –

+0

W moim przypadku jvisualvm 1.7.0 (build 110325) na 64-bitowym Java 1.7.0-b147 daje 16, 16 i 24. Jakie metody używasz do pomiaru z VisualVM? – utapyngo

+0

Możesz nie uzyskiwać dokładnych wyników bez przypisywania wartości do pól elementów "a", "b" i "c". Podstawowa implementacja JVM może nie wymagać, aby faktycznie przydzielić pamięć do pól, które nie są używane, a jedynie alokować pamięć do przechowywania wskaźników do tych pól. –

Odpowiedz

2

Tak wyściółka może się zdarzyć. Możliwe jest również całkowite optymalizowanie obiektów na stosie. Tylko JVM zna dokładne rozmiary w dowolnym momencie. Ponieważ takie techniki przybliżania rozmiaru w obrębie języka Java nie zgadzają się, narzędzia, które dołączają do maszyny JVM, wydają się być najbardziej dokładne. Trzy główne techniki wykonania sizeof ciągu Java, że ​​jestem świadomy są:

  1. serializacji obiektu i powrócić z długością tych bajtów (wyraźnie źle, ale użyteczne dla względnych porównań)
  2. Wykaz egzemplarzy refleksji, i stałe o stałych rozmiarach dla każdego pola znalezionego na obiekcie. Można być dostrojony do być trochę dokładne, ale zmiany w JVM i wypełnienie że JVM mogą lub nie mogą robić będzie go wyrzucić.
  3. przedmiot obci¿aæ obiektów, uruchom GC i porównać zmiany rozmiaru sterty JVM

Żadna z tych technik są dokładne.

Jeśli uruchomiony na Oracle JVM, lub po v1.5. Następnie istnieje sposób na odczytanie rozmiaru obiektu bezpośrednio ze struktury C używanej przez środowisko wykonawcze Java. Nie jest to dobry pomysł na produkcję i pomyl się, bo możesz zawiesić maszynę JVM. Ale tutaj jest wpis na blogu, który może Cię zainteresować, jeśli chcesz go mieć: http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/

Jeśli chodzi o dokumentację tego, co faktycznie robi Java, to jest to specyficzna JVM, specyficzna wersja i potencjalnie specyficzna konfiguracja. Każda implementacja może dowolnie obsługiwać obiekty. Nawet w zakresie całkowitej optymalizacji obiektów, na przykład obiekty, które nie są przekazywane ze stosu, nie mogą być przydzielane na stercie. Niektóre maszyny JVM mogą nawet w całości przechowywać obiekt w rejestrach procesora. Nie w tym przypadku, ale umieszczam go jako przykład, dlaczego uzyskanie prawdziwego rozmiaru obiektów Java jest trudne.

Więc najlepiej przyjmować dowolne wartości sizeof, które można uzyskać ze szczyptą soli i traktować go jako „wytyczne” jedynego pomiaru.

+0

Dodałbym jeszcze jeden punkt do pomiaru wielkości obiektu: przy użyciu pakietu Instrument i metody getObjectSize(). Jak napisano w dokumentacji java, zwraca tylko szacunkowy rozmiar obiektu. Ale myślę, że właśnie to chciałeś powiedzieć "narzędzia, które dołączają do JVM, wydają się być najbardziej dokładne". Sprawdziłem, co robi biblioteka java.sizeof i wygląda na to, że poprawnie używają metody getObjectSize().Spodziewam się, że visualvm zrobi to samo. Więc w przypadku, gdy oba narzędzia wykorzystują instrument java, pozostaje pytanie, dlaczego różne wyniki? Chyba muszę wysłać wiadomość do zespołu Visulvm. –