Zarządzanie pamięcią w Java
Co to jest pamięć stosu?
Stos w Javie to sekcja pamięci zawierająca metody, zmienne lokalne i zmienne referencyjne. Do pamięci stosu odwołuje się zawsze w kolejności „ostatni na wejściu, pierwszy na wyjściu”. Zmienne lokalne są tworzone na stosie.
Co to jest pamięć sterty?
Sterta to sekcja pamięci, która zawiera obiekty i może również zawierać zmienne referencyjne. Zmienne instancji są tworzone w stercie.
Alokacja pamięci w Java
Alokacja pamięci w Java to proces, podczas którego sekcje pamięci wirtualnej są rezerwowane w programie do przechowywania zmiennych oraz instancji struktur i klas. Jednak podczas deklaracji pamięć nie jest przydzielana obiektowi, a jedynie tworzone jest odwołanie. Do alokacji pamięci obiektu używana jest metoda new(), dzięki czemu obiektowi zawsze przydzielana jest pamięć na stercie.
Java Alokacja pamięci podzielona jest na następujące sekcje:
- kupa
- Stos
- Code
- Statyczny
Taki podział pamięci jest niezbędny do jej efektywnego zarządzania.
- kod sekcja zawiera Twoje kod bajtowy.
- Stos zawiera część pamięci metody, zmienne lokalne i zmienne referencyjne.
- kupa sekcja zawiera Obiekty (może również zawierać zmienne referencyjne).
- Statyczny sekcja zawiera Dane/metody statyczne.
Różnica między zmienną lokalną a zmienną instancji
Zmienna instancji jest zadeklarowane wewnątrz klasy, ale nie wewnątrz metody
class Student{ int num; // num is instance variable public void showData{}
Zmienna lokalna są zadeklarowane wewnątrz a metoda m.in metoda argumenty.
public void sum(int a){ int x = int a + 3; // a , x are local variables; }
Różnica między stosem a stertą
Kliknij tutaj jeśli film nie jest dostępny
Weźmy przykład, aby lepiej to zrozumieć. Rozważmy, że Twoja metoda główna wywołuje metodę m1
public void m1{ int x=20 }
Na stosie Java ramka zostanie utworzona metodą m1.
Zmienna X w m1 zostanie również utworzona w ramce dla m1 na stosie. (Patrz obrazek poniżej).
Metoda m1 wywołuje metodę m2. Na stosie Java tworzona jest nowa ramka dla m2 na górze ramki m1.
Zmienne b i c zostaną również utworzone w ramce m2 na stosie.
public void m2(int b){ boolean c; }
Ta sama metoda m2 wywołuje metodę m3. Ponownie ramka m3 jest tworzona na szczycie stosu (patrz poniższy obrazek).
Załóżmy teraz, że nasza metoda m3 tworzy obiekt dla klasy „Konto”, która ma dwa zmienna instancji int p i int q.
Account { Int p; Int q; }
Oto kod metody m3
public void m3(){ Account ref = new Account(); // more code }
Instrukcja new Account() utworzy obiekt konta na stercie.
Zmienna referencyjna „ref” zostanie utworzona na stosie Java.
Operator przypisania „=” utworzy zmienną referencyjną wskazującą na obiekt w stercie.
Gdy metoda zakończy swoje wykonywanie, przepływ sterowania powróci do metody wywołującej. W tym przypadku jest to metoda m2.
Stos z metody m3 zostanie wypłukany.
Ponieważ zmienna referencyjna nie będzie już wskazywała obiektu na stercie, kwalifikowałaby się do odśmiecania.
Gdy metoda m2 zakończy swoje wykonywanie, zostanie ona wyjęta ze stosu, a wszystkie jej zmienne zostaną opróżnione i nie będą już dostępne do użycia.
Podobnie jest w przypadku metody m1.
Ostatecznie przepływ sterowania powróci do punktu początkowego programu. Który zwykle jest metodą „główną”.
Co się stanie, jeśli obiekt ma referencję jako zmienną instancji?
public static void main(String args[]) { A parent = new A(); //more code } class A{ B child = new B(); int e; //more code } class B{ int c; int d; //more code }
W tym przypadku zmienna referencyjna „child” zostanie utworzona w stercie, która z kolei będzie wskazywała na jej obiekt, jak na poniższym schemacie.
Na czym polega zbieranie śmieci Java?
Zbiórka śmieci w Java to proces, dzięki któremu programy automatycznie zarządzają pamięcią. Garbage Collector (GC) znajduje nieużywane obiekty i usuwa je, aby odzyskać pamięć. W Java, dynamiczna alokacja pamięci dla obiektów jest realizowana za pomocą operatora new, który wykorzystuje część pamięci, a pamięć pozostaje przydzielona do momentu, aż pojawią się odwołania do wykorzystania obiektu.
Gdy nie ma żadnych odniesień do obiektu, przyjmuje się, że nie jest on już potrzebny i pamięć zajmowaną przez obiekt można odzyskać. Nie ma wyraźnej potrzeby niszczenia obiektu jako Java automatycznie obsługuje dealokację.
Technika, która pozwala to osiągnąć, nazywa się Zbieranie śmieci. Programy, które nie zwalniają pamięci, mogą w końcu ulec awarii, gdy w systemie zabraknie pamięci do przydzielenia. Mówi się, że te programy mają wycieki pamięci. Zbiórka śmieci w Java dzieje się automatycznie w trakcie istnienia programu, eliminując potrzebę cofania alokacji pamięci i zapobiegając w ten sposób wyciekom pamięci.
W języku C obowiązkiem programisty jest zwolnienie alokacji pamięci przydzielanej dynamicznie za pomocą funkcji free(). To jest gdzie Java prowadzi do zarządzania pamięcią.
Uwaga: Wszystkie obiekty są tworzone w sekcji Heap pamięci. Więcej na ten temat w późniejszym samouczku.
Przykład: Aby nauczyć się mechanizmu zbierania śmieci w Java
Krok 1) Skopiuj poniższy kod do edytora.
class Student{ int a; int b; public void setData(int c,int d){ a=c; b=d; } public void showData(){ System.out.println("Value of a = "+a); System.out.println("Value of b = "+b); } public static void main(String args[]){ Student s1 = new Student(); Student s2 = new Student(); s1.setData(1,2); s2.setData(3,4); s1.showData(); s2.showData(); //Student s3; //s3=s2; //s3.showData(); //s2=null; //s3.showData(); //s3=null; //s3.showData(); } }
Krok 2) Zapisz, skompiluj i uruchom kod. Jak pokazano na schemacie, tworzone są dwa obiekty i dwie zmienne referencyjne.
Krok 3) Odkomentuj wiersz nr 20,21,22. Zapisz, skompiluj i uruchom kod.
Krok 4) Jak pokazano na poniższym diagramie, dwie zmienne referencyjne wskazują na ten sam obiekt.
Krok 5) Odkomentuj wiersze nr 23 i 24. Skompiluj, zapisz i uruchom kod
Krok 6) Jak pokazano na poniższym diagramie, s2 przyjmuje wartość null, ale s3 nadal wskazuje na obiekt i nie kwalifikuje się do usuwania elementów bezużytecznych Java.
Krok 7) Odkomentuj wiersze nr 25 i 26. Zapisz, skompiluj i uruchom kod
Krok 8) W tym momencie nie ma żadnych odniesień wskazujących na obiekt i kwalifikuje się do odśmiecania. Zostanie usunięty z pamięci i nie będzie możliwości jego odzyskania.
Jak usunąć obiekt w Java?
1) Jeśli chcesz, aby Twój obiekt kwalifikował się do zbierania śmieci, przypisz jego zmienną referencyjną wartość null.
2) Typy pierwotne nie są obiektami. Nie można im przypisać wartości null.
Podsumowując:
- Po wywołaniu metody na szczycie stosu tworzona jest ramka.
- Po zakończeniu wykonywania metody przepływ kontroli powraca do metody wywołującej, a odpowiadająca jej ramka stosu jest opróżniana.
- Zmienne lokalne są tworzone na stosie
- Zmienne instancji są tworzone na stercie i są częścią obiektu, do którego należą.
- Zmienne referencyjne są tworzone na stosie.