Wirtualna maszyna Java - zbieranie elementów bezużytecznych
Cykl życia obiektu Java jest zarządzany przez maszynę JVM. Po utworzeniu obiektu przez programistę nie musimy martwić się o resztę jego cyklu życia. JVM automatycznie znajdzie te obiekty, które nie są już używane i odzyska ich pamięć ze sterty.
Wyrzucanie elementów bezużytecznych to poważna operacja wykonywana przez JVM, a dostrojenie jej do naszych potrzeb może znacznie zwiększyć wydajność naszej aplikacji. Istnieje wiele algorytmów czyszczenia pamięci, które są udostępniane przez nowoczesne maszyny JVM. Musimy być świadomi potrzeb naszej aplikacji, aby zdecydować, którego algorytmu użyć.
Nie można programowo zwolnić obiektu w Javie, tak jak w językach innych niż GC, takich jak C i C ++. Dlatego nie możesz mieć wiszących odwołań w Javie. Jednak możesz mieć odwołania o wartości null (odwołania, które odnoszą się do obszaru pamięci, w którym maszyna JVM nigdy nie będzie przechowywać obiektów). Za każdym razem, gdy używane jest odwołanie o wartości null, JVM zgłasza wyjątek NullPointerException.
Zauważ, że chociaż rzadko można znaleźć wycieki pamięci w programach Java dzięki GC, to jednak zdarzają się. Na końcu tego rozdziału utworzymy wyciek pamięci.
Następujące GC są używane w nowoczesnych maszynach JVM
- Kolektor szeregowy
- Kolektor przepustowości
- Kolekcjoner CMS
- Kolektor G1
Każdy z powyższych algorytmów wykonuje to samo zadanie - znajduje obiekty, które nie są już używane i odzyskuje pamięć, którą zajmują na stercie. Jednym z naiwnych podejść do tego byłoby policzenie liczby odniesień, które ma każdy obiekt i zwolnienie go, gdy tylko liczba odniesień zmieni się na 0 (jest to również znane jako liczenie odniesień). Dlaczego jest to naiwne? Rozważ okrągłą listę połączoną. Każdy z jego węzłów będzie miał do niego odniesienie, ale do całego obiektu nie ma odniesienia z dowolnego miejsca i najlepiej byłoby, gdyby został zwolniony.
JVM nie tylko zwalnia pamięć, ale także łączy małe porcje pamięci w większe. Ma to na celu zapobieżenie fragmentacji pamięci.
Krótko mówiąc, typowy algorytm GC wykonuje następujące czynności -
- Znajdowanie nieużywanych obiektów
- Uwalnianie pamięci, którą zajmują w stercie
- Łączenie fragmentów
GC musi zatrzymać wątki aplikacji, gdy jest uruchomione. Dzieje się tak, ponieważ przesuwa obiekty podczas działania, a zatem nie można ich używać. Takie przystanki nazywane są przerwami typu „stop-the-world”, a minimalizowanie częstotliwości i czasu trwania tych pauz jest tym, czego celem jest dostrajanie naszego GC.
Łączenie pamięci
Poniżej przedstawiono prostą demonstrację koalescencji pamięci
Zacieniona część to obiekty, które należy uwolnić. Nawet po odzyskaniu całej przestrzeni możemy przydzielić tylko obiekt o maksymalnym rozmiarze = 75Kb. Dzieje się tak nawet po tym, jak mamy 200 KB wolnego miejsca, jak pokazano poniżej