programowanieProgramista Java

Jak działa mechanizm automatycznego zarządzania pamięcią w Javie (Garbage Collector)?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Javie zarządzanie pamięcią odbywa się dzięki automatycznej zbiórce śmieci (Garbage Collector, GC). JVM samodzielnie śledzi obiekty w pamięci: jeśli obiekt nie ma już więcej odniesień, staje się niedostępny i może zostać usunięty.

GC składa się z różnych faz, takich jak Mark, Sweep i czasami Compact. W fazie Mark obiekty, do których można dotrzeć z korzeni (GC roots), są oznaczane jako żywe. Następnie rozpoczyna się Sweep: nieużywane obiekty są usuwane. Czasami wykonywane jest Compact — defragmentacja pamięci.

Istnieją różne typy GC: Serial, Parallel, CMS, G1. Należy je dobierać w zależności od typu obciążenia aplikacji.

Przykład kodu — sytuacja wycieku pamięci:
List<byte[]> dataList = new ArrayList<>(); while(true) { dataList.add(new byte[1024*1024]); // Obiekty pozostają dostępne }

W tym przykładzie obiekty nigdy nie staną się niedostępne, GC ich nie usunie, co spowoduje OutOfMemoryError.

Pytanie z pułapką

Jeśli obiekt nie ma już żadnych odniesień, kiedy gwarantowane jest wywołanie jego finalizatora (finalize())?

Odpowiedź: Wywołanie metody finalize() wcale nie jest gwarantowane! Może być wywołane nigdy lub z opóźnieniem. Nie można polegać na finalize() w celu zwolnienia zasobów.

@Override protected void finalize() throws Throwable { // Może nie zadziałać! }

Przykłady rzeczywistych błędów z powodu nieznajomości szczegółów tematu


Historia

W dużym systemie e-commerce programiści mieli nadzieję zautomatyzować czyszczenie plików tymczasowych za pomocą metody finalize(), ale z powodu rzadkiego wywoływania tej metody pamięć podręczna została przepełniona plikami tymczasowymi, co doprowadziło do braku miejsca na dysku i przestojów.


Historia

W high-load REST API przypadkowo zapisano wewnętrzną pamięć podręczną odniesień do dużych obiektów, co uniemożliwiło zwolnienie pamięci. Po awarii aplikacji z OutOfMemoryError analiza wykazała błąd w metodzie pamięci podręcznej.


Historia

Finalizatory były używane do zwalniania połączeń sieciowych, uważając to za "pewny sposób". Prowadziło to do sytuacji, w której połączenia utknęły w systemie na nieokreślony czas, powodując blokady i wyczerpanie puli połączeń.