Jak znaleźć wyciek pamięci w Javie (używając na przykład JHat)? Próbowałem załadować zrzut sterty do JHat, aby przyjrzeć się podstawowym. Jednak nie rozumiem, jak mam być w stanie znaleźć odniesienie źródłowe ( ref ) lub jakkolwiek to się nazywa. Zasadniczo mogę powiedzieć, że istnieje kilkaset megabajtów wpisów tablicy skrótów ([java.util.HashMap $ Entry lub coś w tym rodzaju), ale mapy są używane w każdym miejscu ... Czy istnieje sposób na wyszukiwanie dużych map , a może znaleźć ogólne korzenie dużych drzew obiektów?
[Edytuj] Ok, przeczytałem dotychczas odpowiedzi, ale powiedzmy, że jestem tanim draniem (co oznacza, że jestem bardziej zainteresowany nauką korzystania z JHat niż płaceniem za JProfiler). Ponadto JHat jest zawsze dostępny, ponieważ jest częścią JDK. Chyba że, oczywiście, z JHat nie ma innego wyjścia, jak tylko brutalna siła, ale nie mogę uwierzyć, że tak jest.
Nie sądzę też, żebym mógł faktycznie modyfikować (dodając rejestrowanie wszystkich rozmiarów map) i uruchamiać go na tyle długo, bym zauważył wyciek.
źródło
Odpowiedzi:
Używam następującego podejścia do znajdowania wycieków pamięci w Javie. Użyłem jProfilera z dużym sukcesem, ale wierzę, że każde specjalistyczne narzędzie z możliwościami graficznymi (różnice są łatwiejsze do analizy w formie graficznej) będzie działać.
Zasadniczo analiza powinna rozpocząć się od największej pozytywnej różnicy, powiedzmy, typów obiektów i znaleźć przyczynę, dla której te dodatkowe obiekty pozostają w pamięci.
W przypadku aplikacji internetowych, które przetwarzają żądania w kilku wątkach, analiza staje się bardziej skomplikowana, ale nadal obowiązuje podejście ogólne.
Zrobiłem wiele projektów, które miały na celu zmniejszenie zużycia pamięci przez aplikacje i to ogólne podejście z pewnymi poprawkami i sztuczkami specyficznymi dla aplikacji zawsze działało dobrze.
źródło
Odpowiadający tutaj, muszę powiedzieć, że uzyskanie narzędzia, które nie zajmuje 5 minut, aby odpowiedzieć na każde kliknięcie, znacznie ułatwia znalezienie potencjalnych wycieków pamięci.
Ponieważ ludzie sugerują kilka narzędzi (próbowałem tylko wizualnego wm, ponieważ dostałem go w wersji próbnej JDK i JProbe), pomyślałem, że powinienem zasugerować darmowe / otwarte narzędzie zbudowane na platformie Eclipse, Memory Analyzer (czasami określane jako pamięć SAP analizator) dostępny na http://www.eclipse.org/mat/ .
To, co jest naprawdę fajne w tym narzędziu, to to, że zindeksowało zrzut sterty, kiedy go po raz pierwszy otworzyłem, co pozwoliło mu pokazać dane takie jak zachowana sterta bez czekania 5 minut na każdy obiekt (prawie wszystkie operacje były tony szybsze niż inne narzędzia, które wypróbowałem) .
Po otwarciu zrzutu pierwszy ekran pokazuje wykres kołowy z największymi obiektami (licząc zachowaną stertę) i można szybko przejść do obiektów, które są zbyt duże dla wygody. Ma również opcję Znajdź prawdopodobnie podejrzanych o wyciek, która może się przydać, ale ponieważ nawigacja była dla mnie wystarczająca, tak naprawdę nie wdałem się w to.
źródło
HeapDumpOnCtrlBreak
parametrach VM nie jest dostępny . Rozwiązaniem, które znalazłem (do tej pory wciąż szukam) jest użycie JMap do zrzucenia.hprof
pliku, który następnie umieściłem w Eclipse i używam MAT do zbadania.Narzędzie to duża pomoc.
Jednak są chwile, kiedy nie możesz użyć narzędzia: zrzut sterty jest tak duży, że powoduje awarię narzędzia, próbujesz rozwiązać problem z maszyną w jakimś środowisku produkcyjnym, do którego masz tylko dostęp do powłoki itp.
W takim przypadku dobrze jest wiedzieć, jak obejść plik zrzutu hprof.
Szukaj STRON POCZĄTKOWYCH. To pokazuje, które obiekty używają najwięcej pamięci. Ale obiekty nie są grupowane razem wyłącznie według typu: każdy wpis zawiera również identyfikator „śledzenia”. Następnie możesz wyszukać to „TRACE nnnn”, aby zobaczyć kilka górnych ramek na stosie, w których obiekt został przydzielony. Często, gdy widzę, gdzie obiekt jest przydzielony, znajduję błąd i gotowe. Zwróć również uwagę, że możesz kontrolować liczbę klatek zapisywanych w stosie za pomocą opcji -Xrunhprof.
Jeśli sprawdzasz witrynę alokacji i nie widzisz nic złego, musisz rozpocząć łączenie wsteczne od niektórych z tych aktywnych obiektów do obiektów głównych, aby znaleźć nieoczekiwany łańcuch referencyjny. W tym przypadku narzędzie naprawdę pomaga, ale możesz zrobić to samo ręcznie (cóż, za pomocą grep). Nie istnieje tylko jeden obiekt główny (tj. Obiekt nie podlega czyszczeniu). Wątki, klasy i ramki stosu działają jak obiekty główne, a wszystko, do czego silnie się odwołują, nie jest kolekcjonowane.
Aby to zrobić, poszukaj w sekcji HEAP DUMP wpisów o złym identyfikatorze śledzenia. Spowoduje to przejście do wpisu OBJ lub ARR, który zawiera unikalny identyfikator obiektu w postaci szesnastkowej. Wyszukaj wszystkie wystąpienia tego identyfikatora, aby dowiedzieć się, kto ma silne odniesienie do obiektu. Podążaj każdą z tych ścieżek do tyłu, gdy rozgałęziają się, aż dowiesz się, gdzie jest wyciek. Zobacz, dlaczego narzędzie jest tak przydatne?
Statyczne elementy członkowskie są wielokrotnym sprawcą wycieków pamięci. W rzeczywistości nawet bez narzędzia warto poświęcić kilka minut na przejrzenie kodu w poszukiwaniu statycznych członków mapy. Czy mapa może się powiększyć? Czy cokolwiek czyści swoje wpisy?
źródło
jhat
iMAT
najwyraźniej próbuję załadować cały zrzut sterty do pamięci, więc zazwyczaj dochodzi do awarii przyOutOfMemoryError
dużych zrzutach (tj. Z aplikacji, które najbardziej potrzebowały analizy sterty! ). Wydaje się, że NetBeans Profiler używa innego algorytmu do indeksowania odwołań, które mogą działać wolno przy dużych zrzutach, ale przynajmniej nie zużywa nieograniczonej pamięci w narzędziu i powoduje awarię.W większości przypadków w aplikacjach korporacyjnych podana sterta Java jest większa niż idealny rozmiar, wynoszący maksymalnie 12 do 16 GB. Trudno mi było sprawić, by profiler NetBeans działał bezpośrednio w tych dużych aplikacjach Java.
Ale zwykle nie jest to potrzebne. Możesz użyć narzędzia jmap, które jest dostarczane z jdk, aby wykonać "na żywo" zrzut sterty, czyli jmap zrzuci stertę po uruchomieniu GC. Wykonaj jakąś operację na aplikacji, poczekaj, aż operacja zostanie zakończona, a następnie wykonaj kolejny zrzut sterty „na żywo”. Użyj narzędzi takich jak Eclipse MAT, aby załadować zrzuty sterty, posortować na histogramie, zobaczyć, które obiekty wzrosły lub które są najwyższe, to dałoby wskazówkę.
Jest tylko jeden problem z tym podejściem; Ogromne zrzuty sterty, nawet z opcją na żywo, mogą być zbyt duże, aby można je było przenieść na okrążenie programistyczne i mogą wymagać maszyny z wystarczającą ilością pamięci / RAM do otwarcia.
W tym miejscu pojawia się histogram klas. Możesz zrzucić na żywo histogram klas za pomocą narzędzia jmap. Daje to tylko histogram klasy wykorzystania pamięci, ale w zasadzie nie będzie zawierał informacji do łańcucha referencji. Na przykład może umieścić tablicę char na górze. A gdzieś poniżej klasa String. Musisz sam narysować połączenie.
Zamiast pobierać dwa zrzuty sterty, weź dwa histogramy klas, jak opisano powyżej; Następnie porównaj histogramy klas i zobacz klasy, które rosną. Sprawdź, czy możesz powiązać klasy Java z klasami aplikacji. To da całkiem niezłą wskazówkę. Oto skrypt w Pythonie, który pomoże ci porównać dwa zrzuty histogramu jmap. histogramparser.py
Wreszcie narzędzia, takie jak JConolse i VisualVm, są niezbędne, aby zobaczyć wzrost pamięci w czasie i sprawdzić, czy występuje przeciek pamięci. Wreszcie czasami problemem może nie być wyciek pamięci, ale wysokie zużycie pamięci. W tym celu włącz rejestrowanie GC; użyj bardziej zaawansowanego i nowego GC kompaktowania, takiego jak G1GC; i możesz użyć narzędzi jdk, takich jak jstat, aby zobaczyć zachowanie GC na żywo
Inne odniesienia do Google dla -jhat, jmap, Full GC, ogromna alokacja, G1GC
źródło
Istnieją narzędzia, które powinny pomóc Ci znaleźć wyciek, takie jak JProbe, YourKit, AD4J lub JRockit Mission Control. Ta ostatnia to ta, którą osobiście znam najlepiej. Każde dobre narzędzie powinno pozwolić ci przejść do poziomu, na którym można łatwo zidentyfikować wycieki i gdzie są one przydzielone.
Używanie HashTables, Hashmaps lub podobnych jest jednym z niewielu sposobów, w jakie można w ogóle wyciekać pamięć w Javie. Gdybym miał ręcznie znaleźć wyciek, drukowałbym regularnie rozmiar moich HashMaps, a stamtąd znajdowałbym ten, w którym dodaję elementy i zapominam je usunąć.
źródło
Cóż, zawsze istnieje proste rozwiązanie technologiczne polegające na dodawaniu rejestrowania rozmiaru map podczas ich modyfikacji, a następnie przeszukiwaniu dzienników, w których mapy rosną poza rozsądny rozmiar.
źródło
NetBeans ma wbudowany profiler.
źródło
Naprawdę musisz użyć profilera pamięci, który śledzi alokacje. Spójrz na JProfiler - ich funkcja „heap walker” jest świetna i mają integrację ze wszystkimi głównymi środowiskami Java IDE. To nie jest darmowe, ale też nie jest takie drogie (499 USD za jedną licencję) - szybko spalisz 500 USD, starając się znaleźć wyciek za pomocą mniej wyrafinowanych narzędzi.
źródło
Możesz się tego dowiedzieć, mierząc rozmiar użycia pamięci po wielokrotnym wywołaniu modułu odśmiecania pamięci:
Jeśli liczby wyjściowe były równe, nie ma przecieku pamięci w aplikacji, ale jeśli zauważyłeś różnicę między liczbami użycia pamięci (rosnącymi liczbami), w projekcie występuje przeciek pamięci. Na przykład:
Zwróć uwagę, że czasami zwolnienie pamięci przez niektóre czynności, takie jak strumienie i gniazda, zajmuje trochę czasu. Nie powinieneś oceniać na podstawie pierwszych wyników, powinieneś przetestować to w określonym czasie.
źródło
Sprawdź tę obsadę ekranuSprawdź dotyczący znajdowania wycieków pamięci za pomocą JProfiler. To wizualne wyjaśnienie odpowiedzi @Dima Malenko.
Uwaga: chociaż JProfiler nie jest oprogramowaniem darmowym, ale wersja próbna radzi sobie w obecnej sytuacji.
źródło
Ponieważ większość z nas używa już Eclipse do pisania kodu, dlaczego nie skorzystać z narzędzia Memory Analyzer Tool (MAT) w Eclipse. Działa świetnie.
Eclipse MAT to zestaw wtyczek dla Eclipse IDE, która dostarcza narzędzi do analizy
heap dumps
z aplikacji Java oraz określeniememory problems
we wniosku.Pomaga to programiście znaleźć wycieki pamięci dzięki następującym funkcjom
źródło