Jak mogę dowiedzieć się, co trzyma się nieoczyszczonych przedmiotów?

Jeden z naszych programów czasami dostaje błąd OutOfMemory na komputerze jednego użytkownika, ale oczywiście nie kiedy go testuję. Po prostu uruchomiłem go z Jprofilerem (na 10-dniowej licencji ewaluacyjnej, ponieważ nigdy wcześniej go nie używałem), i filtrując na naszym prefiksie kodu, największy kawałek zarówno w całkowitej wielkości, jak i liczbie instancji to 8000 + instancji konkretnej prostej klasy.

Kliknąłem przycisk "Garbage Collect" na Jprofilerze i większość instancji innych naszych klas odeszła, ale nie te konkretne. Uruchomiłem test ponownie, nadal w tej samej instancji i stworzył 4000 + więcej instancji klasy, ale kiedy kliknąłem "Garbage Collect", te odeszły pozostawiając 8000 + oryginalne.

Te instancje utkwiają w różnych kolekcjach na różnych etapach. Zakładam, że fakt, że nie są zbierane śmieci musi oznaczać, że coś trzyma się odniesienia do jednej ze zbiorów, więc to trzyma się odniesienia do przedmiotów.

Any sugestie jak mogę dowiedzieć się, co trzyma się odniesienia? Szukam sugestii, czego szukać w kodzie, a także sposobów, aby to znaleźć w Jprofilerze, jeśli są.

Author: Gray, 2008-09-30

11 answers

Wyrzuć stertę i sprawdź ją.

Jestem pewien, że jest na to więcej niż jeden sposób, ale tutaj jest prosty. Ten opis dotyczy MS Windows, ale podobne kroki można podjąć na innych systemach operacyjnych.
  1. Zainstaluj JDK, jeśli go jeszcze nie masz. Jest wyposażony w kilka zgrabnych narzędzi.
  2. Uruchom aplikację.
  3. Otwórz Menedżera zadań i znajdź identyfikator procesu (PID) dla Javy.exe (lub jakikolwiek plik wykonywalny, którego używasz). Jeśli PID nie są wyświetlane domyślnie użyj widoku > wybierz kolumny... aby je dodać.
  4. zrzuć stertę używając jmap .
  5. Uruchom serwer jhat na wygenerowanym pliku i otwórz przeglądarkę, aby http://localhost:7000 (domyślnym portem jest 7000). Teraz możesz przeglądać typ, który Cię interesuje i informacje, takie jak liczba instancji, co ma do nich odniesienia, itp.

Oto przykład:

C:\dump>jmap -dump:format=b,file=heap.bin 3552

C:\dump>jhat heap.bin
Reading from heap.bin...
Dump file created Tue Sep 30 19:46:23 BST 2008
Snapshot read, resolving...
Resolving 35484 objects...
Chasing references, expect 7 dots.......
Eliminating duplicate references.......
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

Aby to zinterpretować, warto zrozumieć niektóre z nazewnictwo typów tablic Java używa-na przykład wiedząc, że Klasa [Ljava.lang.Obiekt; tak naprawdę oznacza obiekt typu Object [] .

 18
Author: McDowell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 19:28:17

Wypróbuj Eclipse Memory Analyzer. Pokaże ci on dla każdego obiektu, w jaki sposób jest on podłączony do katalogu głównego GC - obiektu, który nie jest zbierany jako śmieci, ponieważ jest przechowywany przez JVM.

Zobacz http://dev.eclipse.org/blogs/memoryanalyzer/2008/05/27/automated-heap-dump-analysis-finding-memory-leaks-with-one-click/{[4]więcej informacji na temat działania Mat Eclipse.

 9
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 19:26:21

Spojrzałbym na Kolekcje (szczególnie statyczne) w Twoich klasach (HashMaps to dobre miejsce na początek). Weźmy ten kod na przykład:

Map<String, Object> map = new HashMap<String, Object>(); // 1 Object
String name = "test";             // 2 Objects
Object o = new Object();          // 3 Objects
map.put(name, o);                 // 3 Objects, 2 of which have 2 references to them

o = null;                         // The objects are still being
name = null;                      // referenced by the HashMap and won't be GC'd

System.gc();                      // Nothing is deleted.

Object test = map.get("test");    // Returns o
test = null;

map.remove("test");               // Now we're down to just the HashMap in memory
                                  // o, name and test can all be GC'd

Tak długo, jak HashMap lub inna kolekcja ma odniesienie do tego obiektu, nie będą zbierane śmieci.

 5
Author: 18Rabbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 18:58:33

Nie ma tam srebrnej kuli, musisz użyć profilera, aby zidentyfikować kolekcje, które przechowują te niepotrzebne obiekty i znaleźć miejsce w kodzie, w którym powinny zostać usunięte. Jak powiedział JesperE, Kolekcje statyczne są pierwszym miejscem, na które warto spojrzeć.

 3
Author: Jacek Szymański,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 18:44:26

Jednym z oczywistych kandydatów są obiekty z finalizatorami. Mogą pozostać, podczas gdy ich metoda finalize jest wywoływana. Należy je zebrać, następnie sfinalizować (zwykle tylko jednym wątkiem finalizera), a następnie ponownie zebrać.

Należy również pamiętać, że można uzyskać OOME, ponieważ gc nie zgromadziło wystarczającej ilości pamięci, mimo że rzeczywiście jest wystarczająco dużo, aby żądanie obiektu zostało utworzone. W przeciwnym razie wydajność zmieliłaby się w ziemi.

 2
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 18:44:23

Miej oko na statyczne kontenery. Wszelkie obiekty w statycznym kontenerze pozostaną tak długo, jak długo Klasa zostanie załadowana.

Edit: usunięto błędną uwagę na WeakReference.

 2
Author: JesperE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 19:10:17

Właśnie czytałem artykuł na ten temat, ale przykro mi, że nie pamiętam gdzie. Myślę, że mogło to być w książce "skuteczna Java". Jeśli znajdę odniesienie, zaktualizuję odpowiedź.

Dwie ważne lekcje to:

1) ostateczne metody mówią GC, co ma zrobić, gdy usuwa obiekt, ale nie prosi go o to, ani nie ma sposobu, aby tego zażądać.

2) współczesnym odpowiednikiem "wycieku pamięci" w niezarządzanych środowiskach pamięci jest zapomniane referencje. Jeśli nie ustawisz wszystkich odwołań do obiektu na null Kiedy skończysz, obiekt nigdy nie zostanie wywołany. Jest to najważniejsze podczas implementacji własnego rodzaju kolekcji lub własnego wrappera, który zarządza kolekcją. Jeśli masz pulę, stos lub kolejkę i nie ustawisz bucket na null po "usunięciu" obiektu z kolekcji, bucket, w którym znajdował się obiekt, utrzyma ten obiekt przy życiu, dopóki nie zostanie ustawiony na odwołaj się do innego obiektu.

Disclaimer: wiem, że inne odpowiedzi o tym wspominały, ale staram się podać więcej szczegółów.

 1
Author: dj_segfault,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 19:20:18

Użyłem Yourkit Java profiler ( http://www.yourkit.com ) do optymalizacji wydajności w Javie 1.5. Ma sekcję dotyczącą pracy nad wyciekami pamięci. Uważam to za przydatne.

Http://www.yourkit.com/docs/75/help/performance_problems/memory_leaks/index.jsp

Możesz otrzymać 15-dniową ocenę: http://www.yourkit.com/download/yjp-7.5.7.exe

BR,
~A

 1
Author: anjanb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 19:30:57

Kolekcje były już wspomniane. Inną trudną do znalezienia lokalizacją jest użycie wielu Classloaderów, ponieważ stary classloader może nie być zbierany, dopóki wszystkie odwołania nie znikną.

Sprawdź też statykę - są paskudne. Frameworki logowania mogą utrzymywać rzeczy otwarte, które mogą przechowywać odniesienia w aplikatorach niestandardowych.

Rozwiązałeś problem?

 1
Author: Thorbjørn Ravn Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-09 07:24:17

Kilka sugestii:

  • nieograniczone mapy używane jako bufory, zwłaszcza gdy statyczne
  • Threadlocal w aplikacjach serwerowych, ponieważ wątki zwykle nie umierają, więc ThreadLocal nie jest zwalniany
  • Interning strings (Strings.intern ()), co powoduje stos łańcuchów w PermSpace
 1
Author: ReneS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-31 01:51:06

Jeśli dostajesz błędy OOM w języku zbieranym ze śmieci, zazwyczaj oznacza to, że część pamięci nie jest rozliczana przez kolektora. Może twoje obiekty posiadają zasoby inne niż java? jeśli tak, to powinni mieć jakąś metodę "zamknij", aby upewnić się, że zasób jest zwolniony, nawet jeśli obiekt Java nie zostanie zebrany wystarczająco szybko.

 0
Author: Javier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 18:37:01