1. Znaczenie mechanizmu recyklingu odpadów Charakterystyczną cechą języka Java jest wprowadzenie mechanizmu garbage collection, który rozwiązuje najtrudniejszy problem zarządzania pamięcią dla programistów C++, dzięki czemu programiści Java nie muszą już brać pod uwagę zarządzania pamięcią podczas pisania programów. Dzięki mechanizmowi garbage collection, obiekty w Javie nie mają już pojęcia "zakresu", jedynie odniesienie obiektu ma "zakres".Garbage collection może skutecznie zapobiegać wyciekom pamięci i efektywnie wykorzystywać pamięć bezczynną.
ps:内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有时也将其称为“对象游离”。
2. Algorytmy w mechanizmach garbage collection Specyfikacja języka Java nie określa wprost, którego algorytmu garbage collection użyć w JVM, ale każdy algorytm garbage collector zazwyczaj musi wykonywać dwie podstawowe funkcje: (1) znajdować bezużyteczne obiekty informacyjne; (2) Odzyskać przestrzeń pamięci zajmowaną przez bezużyteczne obiekty, aby przestrzeń ta była ponownie wykorzystana przez program.
1. Zbieracz liczenia referencyjnego 1.1 Analiza algorytmów
Liczenie referencji to wczesna strategia w garbage collectorach. W tym podejściu dla każdej instancji obiektu w stercie istnieje liczba odniesień. Gdy obiekt zostanie utworzony, a instancja obiektu przypisana do zmiennej, liczba zmiennych jest ustalana na 1. Gdy do tego obiektu przypisana jest dowolna inna zmienna, liczba jest dodawana o 1 (a = b, wtedy licznik instancji obiektu odwołanego przez b wynosi +1), ale gdy odwołanie do instancji obiektu przekroczyło swój czas życia lub zostanie ustawione na nową wartość, licznik odniesień instancji obiektu jest odejmowany o 1. Każda instancja obiektu z licznikiem odniesienia 0 może być zbierana jako śmieci. Gdy instancja obiektu jest zbierana jako garbage, licznik odniesień każdej instancji obiektu, do której się odwołuje, wynosi minus 1. 1.2 Zalety i wady Zasługa:
Collector liczby odniesień może być wykonywany bardzo szybko, wpleciony w proces programu. Jest korzystny w środowiskach czasu rzeczywistego, gdzie programy nie muszą być przerywane przez długi czas. Niedociągnięcie:
Referencji kołowych nie są wykrywane. *Jeśli obiekt nadrzędny ma odniesienie do obiektu potomnego, obiekt potomny z kolei odnosi się do obiektu nadrzędnego. W ten sposób ich liczba cytowań nigdy nie może wynosić 0. 1.3 Algorytm liczenia odniesień nie jest w stanie rozwiązać problemu cyklicznego odniesienia, na przykład:
/** * Java学习交流QQ群:589809992 我们一起学Java! */public class Main { public static void main(String[] args) { MyObject object1 = new MyObject(); MyObject object2 = new MyObject(); object1.object = object2; object2.object = object1; object1 = null; object2 = null; }} Ostatnie dwa zdania przypisują obiekt1 i obiekt2 do null, co oznacza, że obiekty wskazane przez obiekt1 i obiekt2 nie mogą być już dostępne, ale ponieważ odnoszą się do siebie, ich liczniki odniesień nie są 0, więc garbage collector nigdy ich nie powtórzy.
2. Algorytm Traceing Collector lub oznacz i przesuń 2.1 Algorytm wyszukiwania korzeni
Algorytm wyszukiwania pierwiastków został wprowadzony z teorii grafów w matematyce dyskretnej, program traktuje wszystkie relacje referencyjne jako graf, zaczynając od węzła GC ROOT, szukając odpowiadającego mu węzła referencyjnego, po znalezieniu tego węzła, kontynuując poszukiwanie węzła referencyjnego tego węzła, gdy wszystkie węzły odniesienia zostaną przeszukane, pozostałe węzły są traktowane jako niereferencyjne, czyli bezużyteczne. Java, która może być użyta jako korzeń GC 1. Obiekty odwołane w stosie maszyny wirtualnej (tabela zmiennych lokalnych) 2. Obiekt odwołany przez atrybut statyczny w obszarze metody 3. Obiekt odwołany przez stałą w obszarze metody 4. Obiekty odwoływane w lokalnym stosie metod (obiekty natywne)
2.2 Schematyczny diagram algorytmu śledzenia
![]()
2.3 Analiza algorytmu czyszczenia markerów
Algorytm czyszczenia tagów skanuje od kolekcji głównej, oznacza ocalałe obiekty, a następnie skanuje całą przestrzeń pod kątem nieoznaczonych obiektów do recyklingu, jak pokazano na powyższym rysunku. Algorytm czyszczenia tagów nie musi przenosić obiektów i przetwarza jedynie obiekty nieprzetrwające, co jest niezwykle efektywne, gdy istnieje wiele obiektów zachowanych, ale ponieważ algorytm czyszczenia tagów bezpośrednio recyklinguje obiekty niezachowane, powoduje fragmentację pamięci.
3. Algorytm kompaktowania lub algorytm wykańczania etykiet
![]()
Algorytm zakończenia tagów wykorzystuje tę samą metodę co algorytm czyszczenia tagów do oznaczania obiektów, ale różni się ona podczas oczyszczania – po odzyskaniu przestrzeni zajmowanej przez obiekty nieprzetrwające przenosi wszystkie pozostałe obiekty do wolnej przestrzeni po lewym końcu i aktualizuje odpowiadający wskaźnik. Algorytm tag-finish opiera się na algorytmie czyszczenia tagów i przesuwa obiekty, więc jest droższy, ale rozwiązuje problem fragmentacji pamięci. W implementacji kolektorów opartych na algorytmie kompaktowającym zazwyczaj dodaje się uchwyty i tabele uchwytów.
4. Algorytm kopiowania (Compacting Collector)
![]()
Algorytm ten ma na celu pokonanie narzutu uchwytu i rozwiązanie problemu zbierania śmieci z kopicy. Gdy obiekt jest pełny, garbage collection oparty na algorytmie kopiującym skanuje aktywny obiekt z zestawu korzeniowego i kopiuje każdy aktywny obiekt na wolną ścianę (tak aby nie było wolnych luk między pamięcią zajmowaną przez aktywny obiekt), tak że wolna powierzchnia staje się ścianą obiektu, oryginalna ściana obiektu staje się wolną ścianą, a program przydziela pamięć do nowej ściany obiektu. Typową kolekcją śmieci opartą na algorytmie copingu jest algorytm stop-and-copy, który dzieli stos na ściany obiektów i powierzchnie wolne, a program zatrzymuje wykonanie podczas przełączania między ścianami obiektów a powierzchniami wolnymi.
5. Kolekcjoner pokoleniowy
![]()
Strategia recyklingu odpadów pokoleniowych opiera się na fakcie, żeCykl życia różnych obiektów jest inny。 Dlatego obiekty o różnych cyklach życia mogą stosować różne algorytmy recyklingu, aby zwiększyć efektywność recyklingu.
Młode pokolenie 1. Wszystkie nowo wygenerowane obiekty są najpierw umieszczane w młodszym pokoleniu. Celem młodszego pokolenia jest jak najszybsze zbieranie tych przedmiotów o krótkim cyklu życia.
2. Pamięć nowej generacji jest podzielona na jeden region Eden i dwie strefy ocalałych (survivor0, survivor1) zgodnie z proporcją 8:1:1. Jedna strefa Eden, dwie strefy Survivor (ogólnie). Większość obiektów pojawia się w okolicach Eden. Gdy obszar survivor0 również jest pełny, obszar eden i obszar survivor 0 są kopiowane do innego obszaru survivor1, następnie obszary eden i survivor0 są opróżniane, a następnie obszar survivor0 jest pusty, a następnie wymieniane są obszary survivor0 i survivor1. To znaczy, utrzymać pusty obszar Survivor1 i tak dalej.
3. Gdy obszar ocalałego 1 nie wystarcza na przechowywanie ocalałych obiektów z Edena i Survivor0, te ocalałe przedmioty są przechowywane bezpośrednio w starej erze. Jeśli starość jest również pełna, wywoła to pełną GC, czyli nowe pokolenie, a stare pokolenie zostanie poddane recyklingowi
4. GC nowej generacji nazywany jest także Minor GC, a częstotliwość MinorGC jest stosunkowo wysoka (niekoniecznie jest aktywowana, gdy obszar Eden jest pełny)
Stare pokolenie
1. Przedmioty, które przetrwały po doświadczeniu recyklingu śmieci N u młodszego pokolenia, zostaną umieszczone w starszym pokoleniu. Dlatego można uznać, że starsza generacja jest przechowywana w niektórych obiektach o długim cyklu życia.
2. Pamięć jest również znacznie większa niż nowej generacji (przybliżony stosunek to 1:2), gdy pamięć starości jest pełna, wyzwalany jest Major GC, czyli Full GC, częstotliwość Full GC jest stosunkowo niska, czas przeżycia obiektu starego wieku jest stosunkowo długi, a wskaźnik przeżycia wysoki.
Generowanie stałe Używany do przechowywania plików statycznych, takich jak klasy Java, metody itp. Trwałe generacje nie mają istotnego wpływu na garbage collection, ale niektóre aplikacje mogą dynamicznie generować lub wywoływać niektóre klasy, takie jak Hibernate itp., i w tym przypadku trzeba ustawić stosunkowo dużą, trwałą przestrzeń generującą do przechowywania tych nowych klas w czasie działania.
3. GC (Zbieracz śmieci)Kolekcjonery używane przez kolekcjonerów nowej generacji: Serial, PraNew, Parallel Scavenge Kolekcjonery używane przez kolekcjonerów starych czasów: Serial Old, Parallel Old, CMS
![]()
Kolektor szeregowy (algorytm replikacji) Nowa generacja jednogwintowych kolektorów, znakowania i czyszczenia jest jednogwintowana, z korzyścią w postaci prostoty i efektywności.
Serial Old Collector (algorytm etykiet-wykończenie) Kolekcjer pojedynczego nici w stylu starym wieku, wersja kolekcjonera seryjnego dla starego wieku.
Kolektor ParNew (algorytm kopiowania stop) Nowa generacja kolektora można uznać za wielowątkową wersję kolektora szeregowego, która osiąga lepszą wydajność niż szeregowa w środowisku wielordzeniowym procesora.
Równoległy kolektor zbierania (algorytm stop-copy) Kolektory równoległe dla wysokiej przepustowości i efektywnego wykorzystania CPU. Przepustowość wynosi zazwyczaj 99%, a przepustowość = czas wątku użytkownika / (czas wątku użytkownika + czas wątku GC). Nadaje się do scenariuszy takich jak aplikacje tła, które nie wymagają wysokiej interakcji odpowiednio.
Równoległy stary kolektor (algorytm stop-copy) Starsza wersja kolektora Parallel Scavenge, kolektora równoległego, z priorytetem przepustowości
CMS (Concurrent Mark Sweep) Collector (algorytm Mark-Clean) Wysoki współbieżność, niska pauza, dążenie do najkrótszego czasu przerwy odzyskiwania GC, wysokie zużycie CPU, szybki czas reakcji, krótki czas pauzy oraz procesor wielordzeniowy dążący do wysokiego czasu odpowiedzi
4. Mechanizm wdrożenia GCPonieważ obiekt był przetwarzany w różnych pokoleniach, obszar i czas wywozu śmieci również się różnią. Istnieją dwa typy GC: Scavenge GC i Full GC.
Zbieranie GC Zazwyczaj, gdy nowy obiekt zostanie wygenerowany i nie zdobędzie miejsca w Eden, uruchamiany jest GC Scavenge, który oczyszcza obszar Eden, usuwa nieistniejące obiekty i przenosi ocalałe obiekty do obszaru Survivor. Następnie posegreguj dwie strefy Survivor. GC w ten sposób jest wykonywany na obszarze Eden młodszego pokolenia i nie wpływa na starsze pokolenie. Ponieważ większość obiektów zaczyna się z obszaru Eden, a obszar Eden nie jest przydzielany zbyt często, GC obszaru Eden jest wykonywany często. Dlatego zazwyczaj konieczne jest stosowanie szybkich i wydajnych algorytmów, aby jak najszybciej uczynić Eden wolnym.
Pełna GC Uporządkuj cały stos, w tym młodych, stałych i stałych. Full GC jest wolniejszy niż Scavenge GC, ponieważ wymaga recyklingu całego sterta, więc liczba Full GC powinna być jak najbardziej zredukowana. Duża część procesu strojenia JVM to strojenie FullGC. Pełne GC może być spowodowane następującymi przyczynami: 1. Tytuł tenure jest zapisywany w całości 2. Perm jest zapisany w całości 3. System.gc() jest wyświetlany jako wywołanie 4. Strategia alokacji domen w stercie zmienia się dynamicznie po ostatnim GC
5. Java z GC również będzie miała problemy z wyciekiem pamięci1. Użycie statycznych klas kolekcji, takich jak HashMap, Vector itp., jest najbardziej podatne na wycieki pamięci, a cykl życia tych zmiennych statycznych jest taki sam jak w aplikacji, i wszystkie obiekty nie mogą być zwolnione, ponieważ zawsze będą stosowane przez Vector i inne. Wektor statyczny v = nowy Wektor(); dla (int i = 1; i<100; i++) { Object o = nowy Object(); v.add(o); o = null; } W tym przykładzie w stosie kodu znajduje się odniesienie v dla obiektu Wektora oraz odniesienie o dla obiektu Obiekt. W pętli For generujemy nowe obiekty, następnie dodajemy je do obiektu Vector i niwelujemy referencję o (o). Pytanie brzmi: gdy referencja o zostanie znieważona, jeśli GC wystąpi, czy obiekt Object, który stworzyliśmy, może zostać zrecyklowany przez GC? Odpowiedź brzmi: nie. Bo gdy GC śledzi odwołania w stosie kodu, znajduje referencje v, a jeśli dalej śledzisz w dół, odkryjesz, że w przestrzeni pamięci są odwołania do obiektów obiektów, na które wskazuje v referencje. Oznacza to, że nawet jeśli referencja o została opróżniona, nadal istnieją inne odwołania do obiektu, do których można uzyskać dostęp, więc GC nie może ich uwolnić. Jeśli po tej pętli obiekt Object nie ma wpływu na program, zakładamy, że program Java ma wyciek pamięci. 2. Różne połączenia, połączenia bazy danych, sieci, połączenia IO itp. nie pokazują połączenia blisko zamknięcia i nie są recyklingowane przez GC, co skutkuje wyciekiem pamięci. 3. Użycie słuchaczy może również powodować wycieki pamięci, gdy słuchacz nie jest usuwany podczas zwalniania obiektu.
|