W tym artykule znajdziesz odpowiedzi na poniższe pytania:
- Jaki jest podział obszaru pamięci w JVM?
- Czym jest sterta? Jakie dane przechowuje sterta?
- Czym jest stos? Co JVM przechowuje na stosie?
Całą pamięć dzieli się na kilka poziomów. Podstawowym podziałem obszaru pamięci w wirtualnej maszyny Javy jest podział na: sterta i dane poza stertą (pamięć natywną).
Pamięć natywna
W dość mocnym uproszczeniu, w pamięci poza stertą umieszczone są byty potrzebne do wsparcia działania wirtualnej maszyny i reprezentacji jej struktur wewnętrznych. Możemy ją podzielić na 2 grupy: pamięć współdzielona i autonomiczna.
Pamięć współdzielona dzieli się na dodatkowe segmenty: segment Metaspace i segment Code cache. W segmencie Metaspace przechowywane są dane statyczne takie jak: kody klas, metody, pola, literały znakowe, referencje czy stałe. W segmencie Code cache przechowywane są zoptymalizowane i skompilowane kody aplikacji. Ten segment jest mocno powiązany z modułem kompilatora Just-in-Time, który szerzej będzie omówiony w kolejnym artykule.
Kolejną grupą pamięci natywnej jest pamięć autonomiczna, czyli pamięć przypisana do każdego wątku działającego na maszynie wirtualnej. Zawiera ramki wywołań, zmienne lokalne i referencję do aktualnie wykonywanej instrukcji kodu. Schemat pamięci został zaprezentowany poniżej.
Sterta
Drugą i bardziej interesującą częścią pamięci jest sterta. To właśnie tutaj przechowywane są wszystkie instancje klas utworzone w trakcje wykonywania programu. Sterta ma największy wpływ na wydajność aplikacji niezależnie od wybranego języka programowania, ponieważ pamięć w stercie dość często może się zmieniać, ulegać fragmentacji i przepełniać. Obszar pamięci może rosnąć wraz z przydzielaniem i zwiększaniem zasobów dla wirtualnej maszyny Java. Ze względu na konieczność przeglądania całej tej powierzchni, zarządzania nią i w obawie o wydajność aplikacji to podzielono stertę na generacje. Stertę dzieli się na dwie części: przestrzeń dla nowych i starych obiektów, tak jak pokazano to na rysunku poniżej.
Dodatkowo przestań dla nowych obiektów dzielona jest na podprzestrzenie:
- Eden,
- przestrzeń przetrwalników 0,
- przestrzeń przetrwalników 1.
Początkową przestrzenią, przez którą każdy obiekt musi przejść jest Eden. W tym obszarze żyją nowe obiekty. Wraz z działaniem aplikacji, poszczególne obszary będą się zapełniać, aż do momentu uruchamiania mechanizmu oczyszczania pamięci. Mechanizm oczyszczania pamięci usunie nieużywane obiekty w konkretnym obszarze i awansuje do następnej generacji. W każdej z tych części można obrać inną strategię usuwania obiektów i promowania do wyższej generacji. Takie podejście wychodzi z dwóch założeń:
- większość obiektów szybko staje się nieużyteczna z punktu widzenia aplikacji,
- odwołania starych obiektów do nowych są bardzo rzadkie.
Ciekawe artykuły
- D. Rudczyk, Obszary pamięci Maszyny Wirtualnej Javy (JVM), https://softwareskill.pl/obszary-pamieci-maszyny-wirtualnej-javy-jvm
- J.Kubryński, Co każdy programista Java powinien wiedzieć o JVM, https://bottega.com.pl/pdf/materialy/jvm/jvm1.pdf