Hi!

Sa palagay ko hindi ka masyadong magugulat kung sasabihin ko sa iyo na ang iyong computer ay may limitadong dami ng memorya :) Kahit na ang isang hard drive — sa pangkalahatan ay maraming beses na mas malaki kaysa sa imbakan ng RAM — ay maaaring i-pack sa kapasidad ng iyong mga paboritong laro, palabas sa TV, at iba pa. Upang maiwasang mangyari ito, kailangan mong subaybayan ang kasalukuyang estado ng memorya at tanggalin ang mga hindi kinakailangang file mula sa iyong computer. Ano ang kinalaman ng Java programming sa lahat ng ito? Lahat! Pagkatapos ng lahat, kapag ang Java machine ay lumikha ng anumang bagay, ito ay naglalaan ng memorya para sa bagay na iyon.

Sa isang tunay na malaking programa, sampu at daan-daang libong mga bagay ang nilikha, at bawat isa sa kanila ay may sariling piraso ng memorya na inilaan para dito. Ngunit gaano katagal sa tingin mo ang lahat ng mga bagay na ito ay umiiral? "Nabubuhay" ba sila sa buong oras na tumatakbo ang aming programa? Syempre hindi. Kahit na sa lahat ng mga pakinabang ng mga bagay sa Java, ang mga ito ay hindi imortal :) Ang mga bagay ay may sariling lifecycle. Ngayon ay magpapahinga tayo ng kaunti sa pagsulat ng code at titingnan ang prosesong ito :) Bukod dito, napakahalaga para sa iyong pag-unawa sa kung paano gumagana ang isang programa at kung paano pinamamahalaan ang mga mapagkukunan. Kaya, kailan nagsisimula ang buhay ng isang bagay? Tulad ng isang tao - mula sa kanyang kapanganakan, iyon ay, paglikha.


Cat cat = new Cat(); // Here the lifecycle of our Cat object begins!

Una, ang Java Virtual Machine ay naglalaan ng kinakailangang halaga ng memorya upang lumikha ng bagay. Pagkatapos ay lumilikha ito ng isang sanggunian sa memorya na iyon. Sa aming kaso, ang reference na iyon ay tinatawag na cat, para masubaybayan namin ito. Pagkatapos ang lahat ng mga variable nito ay sinisimulan, ang constructor ay tinatawag, at - ta-da! — ang ating bagong gawang bagay ay nabubuhay sa sarili nitong buhay :)

Ang haba ng buhay ng mga bagay ay nag-iiba-iba, kaya hindi kami makakapagbigay ng eksaktong mga numero dito. Sa anumang kaso, nabubuhay ito nang ilang oras sa loob ng programa at gumaganap ng mga function nito. Upang maging tumpak, ang isang bagay ay "buhay" hangga't may mga sanggunian dito. Sa sandaling walang natitirang mga sanggunian, ang bagay ay "namamatay". Halimbawa:


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;

   }

}

Ang Lamborghini Diablo car object ay huminto sa pagiging buhay sa pangalawang linya ng main()pamamaraan. Mayroon lamang isang reference dito, at pagkatapos ay itinakda ang reference na iyon na katumbas ng null. Dahil walang natitirang mga sanggunian sa Lamborghini Diablo, ang inilalaang memorya ay nagiging "basura". Ang isang sanggunian ay hindi kailangang itakda sa null para mangyari ito:


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;
   }

}

Dito lumikha kami ng pangalawang bagay at pagkatapos ay itinalaga ang bagong bagay na ito sa lamborghinireference. Ngayon ang Lamborghini Gallardobagay ay may dalawang sanggunian, ngunit ang Lamborghini Diablobagay ay wala. Ibig sabihin, Diablobasura na ang bagay. Ito ay kapag nagsimula ang built-in na mekanismo ng Java na tinatawag na garbage collector (GC).

Ang garbage collector ay isang panloob na mekanismo ng Java na responsable para sa pagpapalaya ng memorya, ibig sabihin, pag-alis ng mga hindi kinakailangang bagay mula sa memorya. May magandang dahilan kung bakit kami pumili ng larawan ng isang robot vacuum cleaner dito. Pagkatapos ng lahat, gumagana ang tagakolekta ng basura sa halos parehong paraan: sa background, ito ay "naglalakbay" tungkol sa iyong programa, nangongolekta ng basura nang halos walang pagsisikap sa iyong bahagi. Ang trabaho nito ay alisin ang mga bagay na hindi na ginagamit sa programa.

Ang paggawa nito ay nagpapalaya ng memorya sa computer para sa iba pang mga bagay. Naaalala mo ba na sa simula ng aralin sinabi namin na sa ordinaryong buhay kailangan mong subaybayan ang estado ng iyong computer at tanggalin ang mga hindi kinakailangang file? Well, sa kaso ng Java objects, ginagawa ito ng tagakolekta ng basura para sa iyo. Ang tagakolekta ng basura ay tumatakbo nang paulit-ulit habang tumatakbo ang iyong programa: hindi mo kailangang tahasang tawagan ito o bigyan ito ng mga utos, bagama't ito ay posible sa teknikal. Sa ibang pagkakataon, pag-uusapan natin ito nang higit pa at pag-aaralan ang gawain nito nang mas detalyado.

Kapag naabot ng tagakolekta ng basura ang isang bagay, bago sirain ang bagay, tinatawag itong isang espesyal na paraan — finalize()— sa bagay. Ang pamamaraang ito ay maaaring maglabas ng iba pang mga mapagkukunang ginagamit ng bagay. Ang finalize()pamamaraan ay bahagi ng Objectklase. Nangangahulugan iyon na bilang karagdagan sa equals(), hashCode()at toString()mga pamamaraan na nakilala mo dati, ang bawat bagay ay may ganitong pamamaraan. Ito ay naiiba sa iba pang mga pamamaraan dahil ito ay — paano ko ito ilalagay — napaka-kapritsoso.

Sa partikular, hindi ito palaging tinatawag bago ang pagkasira ng isang bagay. Ang programming ay isang tiyak na pagsisikap. Sinasabi ng programmer sa computer na gumawa ng isang bagay, at ginagawa ito ng computer. Sa palagay ko ay nasanay ka na sa ganitong pag-uugali, kaya sa una ay maaaring mahirap para sa iyo na tanggapin ang sumusunod na ideya: "Bago ang pagkasira ng mga bagay, ang finalize()pamamaraan ng Objectklase ay tinatawag. O baka hindi ito tinatawag. Ang lahat ay nakasalalay sa ang swerte mo!"

Gayunpaman, ito ay totoo. Ang Java machine mismo ang nagpapasiya kung tatawagan o hindi ang finalize()pamamaraan sa isang case-by-case na batayan. Halimbawa, subukan nating patakbuhin ang sumusunod na code bilang isang eksperimento:


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; // This is when the first object becomes available to the garbage collector
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Cat object destroyed!");
   }
}

Lumilikha kami ng isang Catbagay at pagkatapos ay sa susunod na linya ng code itinakda namin ang tanging reference nito na katumbas ng null. At ginagawa namin iyon ng isang milyong beses. Tahasang in-overrode namin ang finalize()pamamaraan upang mag-print ito ng string sa console ng isang milyong beses (isang beses sa bawat oras na sinisira nito ang isang Catbagay). Pero hindi! Upang maging tumpak, tumakbo lamang ito ng 37,346 beses sa aking computer! Iyon ay, isang beses lamang sa 27 beses na nagpasya ang Java machine na naka-install sa aking makina na tawagan ang finalize()pamamaraan.

Sa ibang mga kaso, ang koleksyon ng basura ay nangyari nang wala ito. Subukang patakbuhin ang code na ito para sa iyong sarili: malamang, makakakuha ka ng ibang resulta. Tulad ng nakikita mo, finalize()halos hindi matatawag na isang maaasahang kasosyo :) Kaya, isang maliit na payo para sa hinaharap: huwag umasa sa finalize()paraan upang malaya ang mga kritikal na mapagkukunan. Baka tatawagin ito ng JVM, o baka hindi. Sino ang nakakaalam?

Kung habang buhay ang iyong bagay ay nagtataglay ito ng ilang mga mapagkukunan na sobrang mahalaga para sa pagganap, halimbawa, isang bukas na koneksyon sa database, mas mahusay na lumikha ng isang espesyal na paraan sa iyong klase upang palabasin ang mga ito at pagkatapos ay tawagan ito nang tahasan kapag ang bagay ay wala na. kailangan. Sa ganoong paraan malalaman mong tiyak na hindi maghihirap ang pagganap ng iyong programa. Sa simula, sinabi namin na ang pagtatrabaho nang may memorya at pag-alis ng basura ay napakahalaga, at ito ay totoo. Ang hindi wastong pangangasiwa ng mga mapagkukunan at hindi pagkakaunawaan kung paano nililinis ang mga hindi kinakailangang bagay ay maaaring humantong sa mga pagtagas ng memorya. Ito ay isa sa mga pinakakilalang pagkakamali sa programming.

Kung maling isulat ng mga programmer ang kanilang code, maaaring maglaan ng bagong memorya para sa mga bagong likhang bagay sa bawat oras, habang ang mga luma, hindi kinakailangang bagay ay maaaring hindi magagamit para sa pagtanggal ng basurero. Dahil gumawa kami ng analogy sa isang robot vacuum cleaner, isipin kung ano ang mangyayari kung, bago simulan ang robot, ikalat mo ang mga medyas sa paligid ng bahay, basagin ang isang glass vase, at mag-iwan ng Lego building blocks sa buong sahig. Ang robot ay susubukan na gawin ang kanyang trabaho, siyempre, ngunit sa ilang mga punto ito ay makaalis.

Upang payagan ang robot na vacuum cleaner na gumana nang maayos, kailangan mong panatilihing maayos ang sahig at alisin ang anumang bagay na hindi kayang hawakan ng robot. Ang parehong prinsipyo ay nalalapat sa tagakolekta ng basura ng Java. Kung maraming bagay ang natitira sa isang programa na hindi maaaring linisin (tulad ng isang medyas o Lego building block para sa aming robot vacuum cleaner), sa isang punto ay mauubusan ka ng memorya. At maaaring hindi lang ang iyong program ang mag-freeze — maaaring maapektuhan ang lahat ng iba pang program na tumatakbo sa computer. Sila, masyadong, ay maaaring walang sapat na memorya.

Hindi mo kailangang isaulo ito. Kailangan mo lamang na maunawaan ang prinsipyo sa likod kung paano ito gumagana.