Hoi!

Ik denk dat je niet al te verbaasd zult zijn als ik je vertel dat je computer een beperkte hoeveelheid geheugen heeft :) Zelfs een harde schijf - over het algemeen vele malen groter dan RAM-opslag - kan tot de capaciteit worden gevuld met je favoriete games, tv-programma's, en meer. Om dit te voorkomen, moet u de huidige geheugenstatus controleren en onnodige bestanden van uw computer verwijderen. Wat heeft Java-programmering hiermee te maken? Alles! Immers, wanneer de Java-machine een object maakt, wijst het geheugen toe voor dat object.

In een echt groot programma worden tien- en honderdduizenden objecten gemaakt, en aan elk ervan is een eigen stuk geheugen toegewezen. Maar hoe lang denk je dat al deze objecten bestaan? Leven ze de hele tijd dat ons programma draait? Natuurlijk niet. Ondanks alle voordelen van Java-objecten zijn ze niet onsterfelijk :) Objecten hebben hun eigen levenscyclus. Vandaag nemen we een kleine pauze van het schrijven van code en kijken we naar dit proces :) Bovendien is het erg belangrijk voor uw begrip van hoe een programma werkt en hoe bronnen worden beheerd. Dus, wanneer begint het leven van een object? Zoals een persoon - vanaf zijn geboorte, dat wil zeggen schepping.


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

Eerst wijst de Java Virtual Machine de vereiste hoeveelheid geheugen toe om het object te maken. Vervolgens creëert het een verwijzing naar die herinnering. In ons geval heet die referentie cat, zodat we die kunnen bijhouden. Vervolgens worden al zijn variabelen geïnitialiseerd, wordt de constructor aangeroepen en — ta-da! — ons nieuw geslagen object leeft zijn eigen leven :)

De levensduur van objecten varieert, dus we kunnen hier geen exacte cijfers geven. In ieder geval leeft het enige tijd in het programma en voert het zijn functies uit. Om precies te zijn, een object is "levend" zolang er verwijzingen naar zijn. Zodra er geen referenties meer zijn, "sterft" het object. Voorbeeld:


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;

   }

}

Het auto-object Lamborghini Diablo stopt met leven op de tweede regel van de main()methode. Er was maar één verwijzing ernaar en die verwijzing werd gelijk gesteld aan null. Aangezien er geen verwijzingen meer zijn naar de Lamborghini Diablo, wordt het toegewezen geheugen "rommel". Hiervoor hoeft een referentie niet op null te zijn ingesteld:


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

}

Hier hebben we een tweede object gemaakt en dit nieuwe object vervolgens aan de lamborghinireferentie toegewezen. Nu Lamborghini Gallardoheeft het object twee referenties, maar het Lamborghini Diabloobject heeft er geen. Dat betekent dat het Diabloobject nu afval is. Dit is wanneer Java's ingebouwde mechanisme genaamd de Garbage Collector (GC) in het spel komt.

De Garbage Collector is een intern Java-mechanisme dat verantwoordelijk is voor het vrijmaken van geheugen, dwz het verwijderen van onnodige objecten uit het geheugen. Niet voor niets kozen we hier voor een afbeelding van een robotstofzuiger. De vuilnisophaler werkt tenslotte op vrijwel dezelfde manier: op de achtergrond "reist" hij door uw programma en verzamelt hij vrijwel zonder enige inspanning van uw kant afval. Het is zijn taak om objecten te verwijderen die niet langer in het programma worden gebruikt.

Hierdoor wordt geheugen in de computer vrijgemaakt voor andere objecten. Herinner je je dat we aan het begin van de les zeiden dat je in het gewone leven de staat van je computer moet controleren en onnodige bestanden moet verwijderen? Welnu, in het geval van Java-objecten doet de vuilnisman dit voor u. De Garbage Collector wordt herhaaldelijk uitgevoerd terwijl uw programma wordt uitgevoerd: u hoeft het niet expliciet aan te roepen of opdrachten te geven, hoewel dit technisch mogelijk is. Later zullen we er meer over praten en zijn werk in meer detail analyseren.

Wanneer de vuilnisophaler een object bereikt, net voordat het object wordt vernietigd, roept hij een speciale methode — finalize()— op het object aan. Deze methode kan andere bronnen vrijgeven die door het object worden gebruikt. De finalize()methode is onderdeel van de Objectles. Dat betekent dat naast de equals(), hashCode()en toString()methoden die je eerder hebt ontmoet, elk object deze methode heeft. Het verschilt van andere methodes doordat het – hoe zal ik het zeggen – erg wispelturig is.

Het wordt met name niet altijd gebeld vóór de vernietiging van een object. Programmeren is een precieze onderneming. De programmeur vertelt de computer om iets te doen, en de computer doet het. Ik neem aan dat je al aan dit gedrag gewend bent, dus in het begin kan het moeilijk voor je zijn om het volgende idee te accepteren: "Voordat objecten worden vernietigd, wordt de methode finalize()van de Objectklasse aangeroepen. Of misschien wordt deze niet aangeroepen. Het hangt allemaal af van je geluk!"

Toch is het waar. finalize()De Java-machine bepaalt zelf per geval of de methode wordt aangeroepen . Laten we bijvoorbeeld proberen de volgende code als experiment uit te voeren:


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

We maken een Catobject en vervolgens stellen we in de volgende regel code de enige referentie gelijk aan null. En dat doen we een miljoen keer. We hebben de finalize()methode expliciet overschreven zodat deze een miljoen keer een tekenreeks naar de console afdrukt (een keer voor elke keer dat het een Catobject vernietigt). Maar nee! Om precies te zijn, het draaide slechts 37.346 keer op mijn computer! Dat wil zeggen, slechts eens in de 27 keer besloot de Java-machine die op mijn computer was geïnstalleerd om de finalize()methode aan te roepen.

In andere gevallen gebeurde het ophalen van afval zonder. Probeer deze code zelf uit te voeren: hoogstwaarschijnlijk krijgt u een ander resultaat. Zoals u kunt zien, finalize()kan het nauwelijks een betrouwbare partner worden genoemd :) Dus een klein advies voor de toekomst: vertrouw niet op de finalize()methode om kritieke bronnen vrij te maken. Misschien zal de JVM het noemen, of misschien niet. Wie weet?

Als uw object, terwijl het actief is, een aantal bronnen bevat die superbelangrijk zijn voor de prestaties, bijvoorbeeld een open databaseverbinding, is het beter om een ​​speciale methode in uw klasse te maken om ze vrij te geven en deze vervolgens expliciet aan te roepen wanneer het object niet langer actief is. nodig zijn. Zo weet u zeker dat de prestaties van uw programma er niet onder zullen lijden. Vanaf het begin hebben we gezegd dat het werken met geheugen en het verwijderen van afval erg belangrijk is, en dat is waar. Onjuist omgaan met bronnen en verkeerd begrijpen hoe onnodige objecten worden opgeschoond, kan leiden tot geheugenlekken. Dit is een van de meest bekende programmeerfouten.

Als programmeurs hun code verkeerd schrijven, kan er elke keer nieuw geheugen worden toegewezen voor nieuw gemaakte objecten, terwijl oude, onnodige objecten mogelijk niet beschikbaar zijn voor verwijdering door de vuilnisman. Aangezien we een analogie hebben gemaakt met een robotstofzuiger, stel je voor wat er zou gebeuren als je, voordat je de robot start, sokken door het huis strooit, een glazen vaas breekt en lego-bouwstenen op de vloer laat liggen. De robot zal natuurlijk proberen zijn werk te doen, maar op een gegeven moment loopt hij vast.

Om de robotstofzuiger goed te laten werken, moet je de vloer in goede staat houden en alles verwijderen wat de robot niet aankan. Hetzelfde principe is van toepassing op de afvalverzamelaar van Java. Als er in een programma nog veel objecten overblijven die niet kunnen worden opgeschoond (zoals een sok of Lego-bouwsteen voor onze robotstofzuiger), zal je geheugen op een gegeven moment opraken. En het is misschien niet alleen uw programma dat vastloopt - elk ander programma dat op de computer wordt uitgevoerd, kan worden beïnvloed. Ook zij hebben mogelijk niet genoeg geheugen.

U hoeft dit niet te onthouden. U hoeft alleen het principe achter hoe het werkt te begrijpen.