JavaRush /Blog Java /Random-PL /Cykl życia obiektu

Cykl życia obiektu

Opublikowano w grupie Random-PL
Cześć! Myślę, że nie będziesz zbytnio zdziwiony, jeśli powiemy Ci, że pojemność pamięci Twojego komputera jest ograniczona :) Nawet dysk twardy, wielokrotnie większy niż RAM, możesz zapełnić po brzegi ulubionymi grami, serialami, i tak dalej. Aby temu zapobiec, należy monitorować aktualny stan pamięci i usuwać niepotrzebne pliki z komputera. Co ma z tym wspólnego programowanie w Javie? Bezpośredni! W końcu, gdy maszyna Java tworzy dowolny obiekt, przydzielana jest mu pamięć. W naprawdę dużym programie tworzone są dziesiątki i setki tysięcy obiektów, z których każdy ma przydzielony własny fragment pamięci. Cykl życia obiektu - 1Ale jak długo, twoim zdaniem, wszystkie te obiekty istnieją? Czy „żyją” przez cały czas działania naszego programu? Oczywiście że nie. Przy wszystkich zaletach obiektów Java nie są one nieśmiertelne :) Obiekty mają swój własny cykl życia. Dzisiaj zrobimy sobie małą przerwę od pisania kodu i przyjrzymy się temu procesowi :) Ponadto jest to bardzo ważne dla zrozumienia działania programu i zarządzania zasobami. Gdzie zatem zaczyna się życie przedmiotu? Jak człowiek – od urodzenia, czyli stworzenia.
Cat cat = new Cat();//вот сейчас и начался niezbędny цикл нашего obiektа Cat!
Najpierw wirtualna maszyna Java przydziela niezbędną ilość pamięci do utworzenia obiektu. Następnie tworzy link do niego, w naszym przypadku - cataby móc go śledzić. Następnie inicjalizowane są wszystkie zmienne, wywoływany jest konstruktor i oto nasz świeży obiekt już żyje własnym życiem :) Żywotność obiektów jest różna, nie ma tutaj dokładnych liczb. W każdym razie przez jakiś czas żyje wewnątrz programu i wykonuje swoje funkcje. Mówiąc ściślej, obiekt jest „żywy”, dopóki istnieją do niego odniesienia. Gdy nie ma już żadnych powiązań, obiekt „umiera”. Na przykład:
public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");
       lamborghini = null;

   }

}
W metodzie main()obiekt samochodowy Lamborghini Diablo przestaje być żywy już w drugiej linii. Był do niego tylko jeden link, a teraz ten link został przypisany null. Ponieważ nie ma już żadnych wzmianek o Lamborghini Diablo, staje się ono „śmieciem”. Resetowanie łącza nie jest konieczne:
public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");

       Car lamborghiniGallardo = new Car("Lamborghini Gallardo");
       lamborghini = lamborghiniGallardo;
   }

}
Tutaj utworzyliśmy drugi obiekt, po czym wzięliśmy odniesienie lamborghinii przypisaliśmy go do tego nowego obiektu. Istnieją teraz Lamborghini Gallardodwa odniesienia do obiektu, ale Lamborghini Diablożadne nie odnosi się do obiektu. Dlatego obiekt Diablostaje się śmieciem. I w tym momencie zaczyna działać wbudowany w Javę mechanizm zwany Garbage Collectorem, czyli inaczej – Garbage Collector, GC.
Cykl życia obiektu - 2
Garbage Collector to wewnętrzny mechanizm Java, który odpowiada za zwalnianie pamięci, czyli usuwanie z niej niepotrzebnych obiektów. Nie bez powodu wybraliśmy do jego zobrazowania zdjęcie przedstawiające robota sprzątającego. W końcu moduł zbierający śmieci działa mniej więcej w ten sam sposób: w tle „podróżuje” po twoim programie, zbiera śmieci, a jednocześnie praktycznie nie masz z nim interakcji. Jego zadaniem jest usuwanie obiektów, które nie są już używane w programie. W ten sposób zwalnia pamięć w komputerze na inne obiekty. Czy pamiętasz, jak na początku wykładu powiedzieliśmy, że w codziennym życiu trzeba monitorować stan swojego komputera i usuwać stare pliki? Zatem w przypadku obiektów Java moduł zbierający elementy bezużyteczne robi to za Ciebie. Garbage Collector jest uruchamiany wielokrotnie podczas działania Twojego programu: nie trzeba go specjalnie wywoływać i wydawać poleceń, choć jest to technicznie możliwe. Później porozmawiamy o tym więcej i przeanalizujemy bardziej szczegółowo proces jego pracy. W momencie, gdy moduł zbierający śmieci dotrze do obiektu, tuż przed jego zniszczeniem, na obiekcie wywoływana jest specjalna metoda - finalize(). Można go użyć do zwolnienia dodatkowych zasobów, z których korzystał obiekt. Metoda finalize()należy do klasy Object. Oznacza to, że wraz z equals(), hashCode()i toString(), które już spotkałeś wcześniej, ma je każdy obiekt. Różni się od innych metod tym, że jest... jak to ująć... bardzo kapryśna. Mianowicie nie zawsze jest wywoływany przed zniszczeniem obiektu. Programowanie to precyzyjna sprawa. Programista każe komputerowi coś zrobić, a komputer to robi. Prawdopodobnie jesteś już przyzwyczajony do takiego zachowania i na początku może być Ci trudno zaakceptować tę myśl: „Zanim obiekty zostaną zniszczone, wywoływana jest metoda finalize()klasowa Object. Albo nie nazywa się. Jeśli będziemy mieli szczęście!” Jednak to prawda. Maszyna Java sama określa, czy wywołać metodę finalize()w każdym konkretnym przypadku, czy nie. Na przykład spróbujmy uruchomić następujący kod na potrzeby eksperymentu:
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public Cat() {
   }

   public static void main(String[] args) throws Throwable {

       for (int i = 0 ; i < 1000000; i++) {

           Cat cat = new Cat();
           cat = null;//вот здесь первый obiekt становится доступен сборщику мусора
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Объект Cat уничтожен!");
   }
}
Tworzymy obiekt Cati w kolejnej linijce kodu resetujemy jedyne do niego odniesienie. I tak - milion razy. Wyraźnie zastąpiliśmy metodę finalize()i powinna ona wypisać ciąg znaków na konsolę milion razy, za każdym razem przed zniszczeniem obiektu Cat. Ale nie! Mówiąc ściślej, na moim komputerze uruchomiono go tylko 37 346 razy! Oznacza to, że tylko w 1 przypadku na 27 zainstalowana przeze mnie maszyna Java zdecydowała się wywołać metodę finalize()- w pozostałych przypadkach odśmiecanie przebiegało bez tego. Spróbuj uruchomić ten kod samodzielnie: najprawdopodobniej wynik będzie inny. Jak widać finalize()trudno nazwać go wiarygodnym partnerem :) Dlatego mała rada na przyszłość: nie warto polegać na tej metodzie finalize()w przypadku uwolnienia jakichś krytycznych zasobów. Może JVM to wywoła, może nie. Kto wie? Jeśli w ciągu swojego życia obiekt zajmował jakieś zasoby, które były bardzo ważne dla wydajności, na przykład utrzymywał otwarte połączenie z bazą danych, lepiej utworzyć w swojej klasie specjalną metodę, aby je zwolnić i wywołać ją jawnie, gdy obiekt jest Nie jest już potrzebne. W ten sposób będziesz mieć pewność, że wydajność Twojego programu nie ucierpi. Na samym początku powiedzieliśmy, że zarządzanie pamięcią i usuwanie śmieci są bardzo ważne i to prawda. Niewłaściwe obchodzenie się z zasobami i brak zrozumienia procesu składania niepotrzebnych obiektów może prowadzić do wycieków pamięci. To jeden z najbardziej znanych błędów programistycznych. Niepoprawnie napisany kod przez programistę może spowodować, że za każdym razem zostanie przydzielona nowa pamięć dla nowo utworzonych obiektów, a stare, niepotrzebne obiekty nie będą dostępne do usunięcia przez moduł zbierający elementy bezużyteczne. Skoro zrobiliśmy analogię z robotem odkurzającym, wyobraźcie sobie, co by się stało, gdyby przed uruchomieniem robota rozrzucić po domu skarpetki, stłuc szklany wazon i zostawić na podłodze rozłożony zestaw Lego. Robot oczywiście będzie próbował coś zrobić, ale w pewnym momencie utknie.
Cykl życia obiektu - 3
Aby działał prawidłowo, należy utrzymywać podłogę w dobrym stanie i usuwać z niej wszystko, z czym odkurzacz sobie nie radzi. Śmieciarka działa na tej samej zasadzie. Jeśli w programie pozostanie wiele obiektów, których nie może zebrać (np. skarpetka lub klocki Lego do robota sprzątającego), w pewnym momencie pamięć się skończy. I nie tylko napisany program zostanie zawieszony, ale także wszystkie inne programy uruchomione w tym momencie na komputerze. Dla nich też nie będzie wystarczającej ilości pamięci. Tak wygląda cykl życia obiektu i moduł zbierający elementy bezużyteczne w Javie. Nie ma potrzeby zapamiętywania tego: wystarczy zrozumieć zasadę działania. W następnym wykładzie omówimy te procesy bardziej szczegółowo, ale na razie możesz wrócić do rozwiązywania problemów JavaRush :) Powodzenia!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION