Hei!

Jeg tror du ikke vil bli for overrasket hvis jeg forteller deg at datamaskinen din har en begrenset mengde minne :) Selv en harddisk – vanligvis mange ganger større enn RAM-lagring – kan pakkes til kapasitet med favorittspillene dine, TV-programmer, og mer. For å forhindre at dette skjer, må du overvåke den nåværende minnetilstanden og slette unødvendige filer fra datamaskinen. Hva har Java-programmering med alt dette å gjøre? Alt! Når alt kommer til alt, når Java-maskinen oppretter et objekt, tildeler den minne for det objektet.

I et virkelig stort program lages titalls og hundretusener av objekter, og hver av dem har sitt eget minne tildelt for det. Men hvor lenge tror du alle disse gjenstandene eksisterer? Lever de hele tiden programmet vårt kjører? Selvfølgelig ikke. Selv med alle fordelene med Java-objekter, er de ikke udødelige :) Objekter har sin egen livssyklus. I dag tar vi en liten pause fra å skrive kode og ser på denne prosessen :) Dessuten er det veldig viktig for din forståelse av hvordan et program fungerer og hvordan ressurser administreres. Så når begynner livet til en gjenstand? Som en person - fra dens fødsel, det vil si skapelsen.


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

Først tildeler Java Virtual Machine den nødvendige mengden minne for å lage objektet. Deretter oppretter den en referanse til det minnet. I vårt tilfelle heter den referansen cat, så vi kan holde styr på den. Deretter initialiseres alle variablene, konstruktøren kalles, og — ta-da! – vår nypregede gjenstand lever sitt eget liv :)

Levetiden til objekter varierer, så vi kan ikke gi eksakte tall her. I alle fall lever den en stund inne i programmet og utfører funksjonene sine. For å være presis er et objekt "levende" så lenge det er referanser til det. Så snart det ikke er noen referanser igjen, "dør" objektet. Eksempel:


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;

   }

}

Lamborghini Diablo-bilobjektet slutter å være i live på den andre linjen i metoden main(). Det var bare én referanse til den, og da ble den referansen satt lik null. Siden det ikke er noen gjenværende referanser til Lamborghini Diablo, blir det tildelte minnet "søppel". En referanse trenger ikke settes til null for at dette skal skje:


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

}

Her opprettet vi et andre objekt og tilordnet deretter dette nye objektet til referansen lamborghini. Nå Lamborghini Gallardohar objektet to referanser, men Lamborghini Diabloobjektet har ingen. Det betyr at Diabloobjektet nå er søppel. Det er da Javas innebygde mekanisme kalt garbage collector (GC) kommer inn i bildet.

Søppelsamleren er en intern Java-mekanisme som er ansvarlig for å frigjøre minne, dvs. fjerne unødvendige gjenstander fra minnet. Det er en god grunn til at vi valgte et bilde av en robotstøvsuger her. Tross alt fungerer søppelsamleren omtrent på samme måte: i bakgrunnen "reiser" den rundt programmet ditt, og samler søppel med praktisk talt ingen innsats fra din side. Dens jobb er å fjerne objekter som ikke lenger brukes i programmet.

Ved å gjøre dette frigjøres minne i datamaskinen for andre objekter. Husker du at vi i begynnelsen av leksjonen sa at i det vanlige livet må du overvåke tilstanden til datamaskinen din og slette unødvendige filer? Vel, i tilfelle av Java-objekter, gjør søppelsamleren dette for deg. Søppelsamleren kjører gjentatte ganger mens programmet kjører: du trenger ikke eksplisitt kalle det eller gi det kommandoer, selv om dette er teknisk mulig. Senere vil vi snakke mer om det og analysere arbeidet i større detalj.

Når søppelsamleren når en gjenstand, like før den ødelegger gjenstanden, kaller den en spesiell metode — finalize()— på gjenstanden. Denne metoden kan frigjøre andre ressurser som brukes av objektet. Metoden finalize()er en del av Objectklassen. Det betyr at i tillegg til equals(), hashCode()og toString()metodene du møtte tidligere, har hvert objekt denne metoden. Den skiller seg fra andre metoder ved at den er – hvordan skal jeg si dette – veldig lunefull.

Spesielt kalles det ikke alltid før ødeleggelsen av et objekt. Programmering er et presist forsøk. Programmereren ber datamaskinen gjøre noe, og datamaskinen gjør det. Jeg antar at du allerede er vant til denne oppførselen, så til å begynne med kan det være vanskelig for deg å akseptere denne ideen: "Før ødeleggelsen av objekter, kalles metoden finalize()til Objectklassen. Eller kanskje den ikke kalles. Alt avhenger av lykken din!"

Likevel er det sant. Java-maskinen bestemmer selv om finalize()metoden skal kalles opp fra sak til sak. La oss for eksempel prøve å kjøre følgende kode som et eksperiment:


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!");
   }
}

Vi lager et Catobjekt, og i neste kodelinje setter vi dens eneste referanse lik null. Og det gjør vi en million ganger. Vi har eksplisitt overstyrt finalize()metoden slik at den skriver ut en streng til konsollen en million ganger (en gang for hver gang den ødelegger et Catobjekt). Men nei! For å være presis, kjørte den bare 37 346 ganger på datamaskinen min! Det vil si at bare én av 27 ganger bestemte Java-maskinen installert på maskinen min å kalle metoden finalize().

I andre tilfeller skjedde søppelhenting uten. Prøv å kjøre denne koden selv: mest sannsynlig vil du få et annet resultat. Som du kan se, finalize()kan neppe kalles en pålitelig partner :) Så, et lite råd for fremtiden: ikke stol på metoden finalize()for å frigjøre kritiske ressurser. Kanskje JVM vil kalle det, eller kanskje ikke. Hvem vet?

Hvis mens objektet ditt er i live, inneholder det noen ressurser som er superviktige for ytelsen, for eksempel en åpen databaseforbindelse, er det bedre å lage en spesiell metode i klassen din for å frigjøre dem og deretter kalle den eksplisitt når objektet ikke lenger er det behov for. På den måten vil du være sikker på at programmets ytelse ikke vil lide. Fra første stund sa vi at det å jobbe med hukommelse og fjerne søppel er veldig viktig, og det stemmer. Feil håndtering av ressurser og misforståelse av hvordan unødvendige gjenstander ryddes opp kan føre til minnelekkasjer. Dette er en av de mest kjente programmeringsfeilene.

Hvis programmerere skriver koden feil, kan nytt minne tildeles for nyopprettede objekter hver gang, mens gamle, unødvendige objekter kanskje ikke er tilgjengelige for fjerning av søppelsamleren. Siden vi laget en analogi med en robotstøvsuger, forestill deg hva som ville skje hvis du, før du starter roboten, strør sokker rundt i huset, knuser en glassvase og legger igjen en Lego-byggeklosser over hele gulvet. Roboten vil selvfølgelig prøve å gjøre jobben sin, men på et tidspunkt vil den sette seg fast.

For å la robotstøvsugeren fungere skikkelig, må du holde gulvet i god stand og fjerne alt som roboten ikke kan håndtere. Det samme prinsippet gjelder for Javas søppelsamler. Hvis det er mange gjenstander igjen i et program som ikke kan ryddes opp (som en sokk eller Lego-byggekloss til vår robotstøvsuger), vil du på et tidspunkt gå tom for minne. Og det er kanskje ikke bare programmet ditt som vil fryse - alle andre programmer som kjører på datamaskinen kan bli påvirket. De har kanskje ikke nok hukommelse også.

Du trenger ikke å huske dette. Du trenger bare å forstå prinsippet bak hvordan det fungerer.