JavaRush /Blog Java /Random-PL /Przewodnik po zarządzaniu pamięcią Java (i zapisywaniu ko...
pandaFromMinsk
Poziom 39
Минск

Przewodnik po zarządzaniu pamięcią Java (i zapisywaniu kodu)

Opublikowano w grupie Random-PL
Notatka tłumacza: chęć przetłumaczenia notatki pojawiła się wczesnym czerwcowym rankiem, po przeczytaniu jej na wpół śpiącej w wagonie metra. Grupa docelowa: osoby, które stawiają swoje pierwsze kroki w świecie Java i ze względu na charakter swojego podstawowego wykształcenia technicznego lub chęci bardzo chcą poznać Javę i poznać wszystkie procesy „elektrodynamiczne”. Jestem pewien, że dla tych, którzy to przeczytają, będzie to punkt wyjścia do podróży w świat konfiguracji JVM i GC. Dobry wiatr! Oryginalny artykuł tutaj Jako programista spędzasz niezliczone godziny na usuwaniu błędów z aplikacji Java i zapewnianiu wydajności tam, gdzie jest potrzebna. Podczas testowania zauważasz, że aplikacja stopniowo działa wolniej, aż w końcu całkowicie się zawiesza lub po prostu wykazuje słabą wydajność. W końcu zaakceptuj fakt, że zdarzają się wycieki pamięci. Garbage Collector Java dokłada wszelkich starań, aby uporać się z tymi wyciekami. Jednak w obliczu takich sytuacji można zrobić tylko kilka rzeczy. Potrzebujesz sposobów identyfikowania wywołań wycieków pamięci, identyfikowania przyczyn i zrozumienia roli modułu zbierającego elementy bezużyteczne Java w wpływaniu na ogólną wydajność aplikacji.

Główne objawy wycieków pamięci Java

Istnieje kilka symptomów wskazujących, że w aplikacji występują problemy z wyciekiem pamięci. Nieznaczny spadek wydajności, a nie nagła awaria aplikacji, wskazuje jedynie na wyciek pamięci. Problem może pojawiać się za każdym razem podczas pracy lub dopiero wtedy, gdy aplikacja zacznie pracować z dużą ilością danych lub odwrotnie, zaczniesz skalować aplikację. Aplikacja prawdopodobnie wyświetli błąd braku pamięci, gdy wyciek zużyje wszystkie dostępne zasoby pamięci. Jeśli ponownie uruchomisz aplikację i będziesz mieć nadzieję, że wszystko będzie dobrze, będziesz napotykać powtarzające się awarie, dopóki wyciek nie zostanie naprawiony. Ogólnie rzecz biorąc, wycieki pamięci mają miejsce, gdy zamiast zwalniać pamięć, gromadzą się odniesienia do obiektów. Zajmują całą dostępną pamięć i uniemożliwiają aplikacji dostęp do potrzebnych jej zasobów.

Błędy konfiguracji pojawiające się jako wycieki pamięci

Zanim przyjrzysz się sytuacjom powodującym problemy z pamięcią Java i przeprowadzisz analizę, musisz upewnić się, że badania nie dotyczą zupełnie innego problemu. Niektóre błędy braku pamięci wynikają z różnych błędów, takich jak błędy konfiguracji. W aplikacji może brakować pamięci sterty lub może powodować konflikt z innymi aplikacjami w systemie. Jeśli zaczniesz mówić o problemach z małą ilością pamięci, ale nie możesz dowiedzieć się, co jest przyczyną wycieku, spójrz na aplikację inaczej. Przekonasz się, że będziesz musiał dokonać zmian w wątku finalizacyjnym lub zwiększyć ilość trwałej przestrzeni generacyjnej, czyli obszaru pamięci JVM służącego do przechowywania opisów klas Java i niektórych dodatkowych danych.

Korzyści z narzędzi do monitorowania pamięci

Narzędzia do monitorowania pamięci zapewniają lepszy wgląd w wykorzystanie dostępnych zasobów przez aplikację Java. Korzystając z tego oprogramowania, robisz krok w kierunku zawężenia poszukiwań źródła problemu wycieków pamięci i innych incydentów wydajnościowych. Narzędzia są podzielone na kilka kategorii i może być konieczne użycie różnych aplikacji, aby dowiedzieć się, jak prawidłowo zgłosić problem i co poszło nie tak, nawet jeśli masz do czynienia z wyciekami pamięci. Pliki zrzutu sterty dostarczają informacji niezbędnych do analizy pamięci Java. W takim przypadku musisz użyć dwóch narzędzi: jednego do wygenerowania pliku zrzutu i drugiego do szczegółowej analizy. Rozwiązanie to dostarcza szczegółowych informacji o tym co dzieje się z aplikacją. Gdy narzędzie wskaże lokalizacje możliwych problemów i zawęzi obszar, aby odkryć dokładną lokalizację zdarzenia. I ten okres to czas najdłuższej i najbardziej obciążającej nastrój części próby i błędu. Analizator pamięci wskazuje kilka problemów w kodzie, ale nie masz całkowitej pewności, jakie problemy napotyka Twoja aplikacja. Jeśli nadal napotykasz ten sam błąd, zacznij od nowa i popracuj nad innym możliwym błędem. Wprowadzaj jedną zmianę na raz i spróbuj zduplikować błąd. Aby zduplikować warunki błędu, będziesz musiał pozwolić aplikacji działać przez jakiś czas. Jeśli podczas pierwszego testu nastąpi wyciek pamięci, pamiętaj o przeprowadzeniu testu ładowania aplikacji. Aplikacja może działać dobrze z małą ilością danych, ale może ponownie generować te same błędy podczas pracy z dużą ilością danych. Jeśli ten sam błąd nadal występuje, musisz zacząć od nowa i poszukać innej możliwej przyczyny. Narzędzia do monitorowania pamięci okazują się przydatne, gdy aplikacja jest już w pełni sprawna. Możesz zdalnie monitorować wydajność JVM i proaktywnie wykrywać sytuacje awaryjne, zanim programista zagłębi się w problem i zbierze historyczne dane dotyczące wydajności, aby pomóc w ulepszeniu technik programowania w przyszłości i sprawdzić, jak Java działa pod dużym obciążeniem. Wiele rozwiązań obejmuje tryby ostrzegania o „niebezpieczeństwie” lub inne podobne tryby, dzięki czemu programista może natychmiast wiedzieć, co się dzieje. Każdy programista nie chce, aby krytyczna aplikacja w środowisku produkcyjnym uległa awarii i spowodowała utratę dziesiątek lub setek tysięcy dolarów w czasie przestoju aplikacji, dlatego narzędzia do monitorowania pamięci skracają czas reakcji programisty. Aplikacje monitorujące pamięć pozwalają na błyskawiczne rozpoczęcie procesu diagnostycznego, zamiast prosić Cię o udanie się do klienta, gdzie nikt Ci nie powie dokładnie jaki błąd się wydarzył i jaki kod błędu wygenerowała aplikacja. Jeśli często borykasz się z problemami z pamięcią i wydajnością aplikacji Java, przyjrzyj się dokładnie procesowi testowania. Zidentyfikuj każdy słaby obszar w procesie rozwoju i zmień swoje strategie testowania. Skonsultuj się ze współpracownikami i porównaj swoje podejścia do testowania z istniejącymi najlepszymi praktykami. Czasami trzeba poprawić mały fragment kodu, a następnie zapewnić trwały wpływ na całą aplikację.

Rola modułu zbierającego śmieci w pamięci Java i wyciekach pamięci

Garbage Collector w Javie odgrywa kluczową rolę w wydajności aplikacji i wykorzystaniu pamięci. Wyszukuje nieużywane (martwe) obiekty i usuwa je. Obiekty te nie zajmują już pamięci, więc aplikacja w dalszym ciągu zapewnia dostępność zasobów. Czasami aplikacja nie daje GC wystarczającej ilości czasu lub zasobów na usunięcie martwych obiektów i gromadzą się one. Może się zdarzyć, że będziesz mieć aktywny dostęp do obiektów, które Twoim zdaniem są martwe. Śmieciarz nie może nic z tym zrobić, ponieważ... jego zautomatyzowany mechanizm zarządzania pamięcią omija aktywne obiekty. Zwykle moduł zbierający elementy bezużyteczne działa autonomicznie, ale należy dostosować jego zachowanie, aby reagował na poważne problemy z pamięcią. Jednak sam GC może powodować problemy z wydajnością.

Obszary GC

Moduł zbierający elementy bezużyteczne dzieli obiekty na różne obszary, aby zoptymalizować montaż. Młode Pokolenie prezentuje obiekty, które szybko wymierają. Śmieciarz często pracuje w tym obszarze od chwili, gdy musi posprzątać. Obiekty, które po osiągnięciu określonego czasu pozostają żywe, przechodzą do Starej Generacji. W obszarze Starej Generacji obiekty pozostają długo i nie są tak często usuwane przez kolekcjonera. Jeśli jednak moduł zbierający działa w zakresie, aplikacja przechodzi dużą operację, podczas której moduł zbierający przegląda aktywne obiekty w celu usunięcia śmieci. W rezultacie obiekty aplikacyjne znajdują się w końcowym obszarze trwałej generacji. Zazwyczaj obiekty te zawierają niezbędne metadane JVM. Aplikacja nie generuje dużo śmieci w trybie Permanent Generation, ale potrzebuje modułu zbierającego, aby usuwać klasy, gdy nie są już potrzebne.

Zależność pomiędzy modułem Garbage Collector a czasem reakcji

Moduł zbierający elementy bezużyteczne niezależnie od priorytetu wykonania wątków aplikacji zatrzymuje je bez oczekiwania na zakończenie. Zjawisko to nazywane jest wydarzeniem „Zatrzymaj Świat”. Region Young Generation modułu zbierającego elementy bezużyteczne ma niewielki wpływ na wydajność, ale problemy są zauważalne, jeśli GC wykonuje intensywne czyszczenie. Dojdziesz do sytuacji, w której podrzędne GC Młodego Pokolenia ciągle działa lub Stare Pokolenie przechodzi w stan niekontrolowany. W takiej sytuacji należy zrównoważyć częstotliwość Młodej Generacji z wydajnością wymagającą zwiększenia powierzchni tego kolektora. Regiony Permanent Generation i Old Generation modułu wyrzucania elementów bezużytecznych mają znaczący wpływ na wydajność aplikacji i użycie pamięci. Ta główna operacja oczyszczania śmieci przechodzi przez stertę w celu wypchnięcia martwych obiektów. Proces trwa dłużej niż drobna kompilacja, a wpływ na wydajność może potrwać dłużej. Gdy intensywność szorowania jest wysoka, a obszar Starej Generacji jest duży, wydajność całej aplikacji spada z powodu zdarzeń „Zatrzymaj świat”. Optymalizacja usuwania elementów bezużytecznych wymaga monitorowania częstotliwości uruchamiania programu, wpływu na ogólną wydajność oraz sposobu dostosowywania ustawień aplikacji w celu zmniejszenia częstotliwości monitorowania. Może zaistnieć potrzeba zidentyfikowania tego samego obiektu umieszczonego więcej niż raz, bez konieczności odgradzania się aplikacji od umieszczenia, lub może zaistnieć potrzeba znalezienia punktów kompresji, które wstrzymują cały system. Uzyskanie właściwej równowagi wymaga zwrócenia szczególnej uwagi na wszystko, od obciążenia procesora po cykle modułu wyrzucania elementów bezużytecznych, zwłaszcza jeśli młode i starsze pokolenie nie są zrównoważone. Rozwiązanie problemu wycieków pamięci i optymalizacja usuwania elementów bezużytecznych pomaga poprawić wydajność aplikacji Java. Dosłownie żonglujesz wieloma ruchomymi częściami. Jednak dzięki odpowiedniemu podejściu do rozwiązywania problemów i narzędziom analitycznym zapewniającym rygorystyczną widoczność, dotrzesz do światła na końcu tunelu. W przeciwnym razie będziesz cierpieć na problemy związane z wydajnością. Staranne rozmieszczenie i monitorowanie pamięci odgrywają kluczową rolę w aplikacji Java. Aby zoptymalizować aplikację i uniknąć błędów związanych z brakiem pamięci, musisz przejąć pełną kontrolę nad interakcją pomiędzy zbieraniem elementów bezużytecznych, usuwaniem obiektów i wydajnością. Narzędzia do monitorowania pomagają być na bieżąco z potencjalnymi problemami i identyfikować trendy wykorzystania pamięci, dzięki czemu można przyjąć proaktywne podejście do rozwiązywania problemów. Wycieki pamięci często pokazują nieskuteczność rozwiązywania problemów w zwykły sposób, zwłaszcza jeśli napotkasz nieprawidłowe wartości parametrów konfiguracyjnych, ale rozwiązywanie problemów związanych z pamięcią może pomóc szybko uniknąć zdarzeń, które staną Ci na drodze. Perfekcja dostrajania pamięci Java i GC znacznie ułatwia proces programowania.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION