Hej!

Jag tror att du inte kommer att bli alltför förvånad om jag berättar att din dator har en begränsad mängd minne :) Till och med en hårddisk — i allmänhet många gånger större än RAM-lagring — kan packas till kapacitet med dina favoritspel, TV-program, och mer. För att förhindra att detta händer måste du övervaka minnets nuvarande tillstånd och ta bort onödiga filer från din dator. Vad har Java-programmering med allt detta att göra? Allt! När allt kommer omkring, när Java-maskinen skapar något objekt, allokerar den minne för det objektet.

I ett riktigt stort program skapas tiotals och hundratusentals objekt, och vart och ett av dem har sitt eget minne tilldelat för det. Men hur länge tror du att alla dessa föremål finns? Lever de hela tiden vårt program körs? Självklart inte. Även med alla fördelar med Java-objekt är de inte odödliga :) Objekt har sin egen livscykel. Idag tar vi en liten paus från att skriva kod och tittar på denna process :) Dessutom är det väldigt viktigt för din förståelse för hur ett program fungerar och hur resurser hanteras. Så när börjar livet för ett föremål? Som en person — från dess födelse, det vill säga skapelsen.


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

Först tilldelar Java Virtual Machine den nödvändiga mängden minne för att skapa objektet. Sedan skapar den en referens till det minnet. I vårt fall heter den referensen , catså vi kan hålla reda på den. Sedan initieras alla dess variabler, konstruktorn anropas och — ta-da! — vårt nypräglade föremål lever sitt eget liv :)

Livslängden på föremål varierar, så vi kan inte ge exakta siffror här. I vilket fall som helst lever den en tid inne i programmet och utför sina funktioner. För att vara exakt är ett objekt "levande" så länge det finns referenser till det. Så fort det inte finns några referenser kvar "dör objektet". Exempel:


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;

   }

}

Bilobjektet Lamborghini Diablo slutar vara vid liv på den andra raden av metoden main(). Det fanns bara en referens till det, och sedan sattes den referensen lika med null. Eftersom det inte finns några kvarvarande referenser till Lamborghini Diablo, blir det tilldelade minnet "skräp". En referens behöver inte vara inställd på null för att detta ska hända:


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

}

Här skapade vi ett andra objekt och tilldelade sedan detta nya objekt till referensen lamborghini. Nu Lamborghini Gallardohar objektet två referenser, men Lamborghini Diabloobjektet har ingen. Det betyder att Diabloföremålet nu är skräp. Det är då Javas inbyggda mekanism som kallas garbage collector (GC) kommer in i bilden.

Skräpsamlaren är en intern Java-mekanism som ansvarar för att frigöra minne, det vill säga att ta bort onödiga föremål från minnet. Det finns en bra anledning till att vi valde en bild på en robotdammsugare här. När allt kommer omkring fungerar sophämtaren på ungefär samma sätt: i bakgrunden "färdas" den runt ditt program och samlar skräp med praktiskt taget ingen ansträngning från din sida. Dess uppgift är att ta bort objekt som inte längre används i programmet.

Om du gör detta frigörs minne i datorn för andra objekt. Kommer du ihåg att vi i början av lektionen sa att du i det vanliga livet måste övervaka din dators tillstånd och radera onödiga filer? Tja, när det gäller Java-objekt, gör sopsamlaren detta åt dig. Sophämtaren körs upprepade gånger medan ditt program körs: du behöver inte uttryckligen kalla det eller ge det kommandon, även om detta är tekniskt möjligt. Senare kommer vi att prata mer om det och analysera dess arbete mer i detalj.

När sopsamlaren når ett föremål, precis innan det förstörs, anropar den en speciell metod — — finalize()på föremålet. Denna metod kan frigöra andra resurser som används av objektet. Metoden finalize()är en del av Objectklassen. Det betyder att förutom de equals(), hashCode()och toString()metoder som du träffade tidigare, har varje objekt denna metod. Det skiljer sig från andra metoder genom att det är - hur ska jag uttrycka detta - väldigt nyckfullt.

I synnerhet kallas det inte alltid före förstörelsen av ett föremål. Programmering är en exakt strävan. Programmeraren säger åt datorn att göra något, och datorn gör det. Jag antar att du redan är van vid det här beteendet, så till en början kan det vara svårt för dig att acceptera följande idé: "Innan förstörelsen av objekt anropas klassens metod. Eller så kallas den inte. Allt finalize()beror Objectpå din tur!"

Ändå är det sant. Java-maskinen avgör själv om finalize()metoden ska anropas eller inte från fall till fall. Låt oss till exempel försöka köra följande kod som ett experiment:


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 skapar ett Catobjekt och sedan på nästa rad kod sätter vi dess enda referens lika med null. Och det gör vi en miljon gånger. Vi åsidosatte uttryckligen finalize()metoden så att den skriver ut en sträng till konsolen en miljon gånger (en gång för varje gång den förstör ett Catobjekt). Men nej! För att vara exakt körde den bara 37 346 gånger på min dator! Det vill säga, bara en gång av 27 gånger bestämde sig Java-maskinen som var installerad på min maskin för att anropa metoden finalize().

I andra fall skedde sophämtning utan det. Försök att köra den här koden själv: troligtvis kommer du att få ett annat resultat. Som du kan se, finalize()kan knappast kallas en pålitlig partner :) Så, ett litet råd för framtiden: lita inte på metoden finalize()för att frigöra kritiska resurser. Kanske kommer JVM att kalla det, eller kanske inte. Vem vet?

Om medan ditt objekt är vid liv innehåller det några resurser som är superviktiga för prestanda, till exempel en öppen databasanslutning, är det bättre att skapa en speciell metod i din klass för att släppa dem och sedan anropa det explicit när objektet inte längre finns behövs. På så sätt vet du säkert att ditt programs prestanda inte kommer att bli lidande. Redan från början sa vi att det är väldigt viktigt att arbeta med minne och ta bort skräp, och det är sant. Felaktig hantering av resurser och missförstånd av hur onödiga föremål rensas upp kan leda till minnesläckor. Detta är ett av de mest kända programmeringsmisstagen.

Om programmerare skriver sin kod felaktigt kan nytt minne allokeras för nyskapade objekt varje gång, medan gamla, onödiga objekt kanske inte är tillgängliga för borttagning av sophämtaren. Eftersom vi gjorde en analogi med en robotdammsugare, föreställ dig vad som skulle hända om du, innan du startar roboten, strör strumpor runt huset, krossar en glasvas och lämnar en Lego-byggklossar över hela golvet. Roboten kommer förstås att försöka göra sitt jobb, men någon gång kommer den att fastna.

För att robotdammsugaren ska fungera korrekt måste du hålla golvet i gott skick och ta bort allt som roboten inte kan hantera. Samma princip gäller för Javas sophämtare. Om det finns många föremål kvar i ett program som inte går att städa upp (som en strumpa eller legobyggkloss till vår robotdammsugare) kommer du någon gång att få slut på minne. Och det kanske inte bara är ditt program som kommer att frysa - alla andra program som körs på datorn kan påverkas. De kanske också inte har tillräckligt med minne.

Du behöver inte memorera detta. Du behöver bara förstå principen bakom hur det fungerar.