Hallo!

Ich denke, Sie werden nicht allzu überrascht sein, wenn ich Ihnen sage, dass Ihr Computer nur über eine begrenzte Speicherkapazität verfügt :) Sogar eine Festplatte – in der Regel um ein Vielfaches größer als der RAM-Speicher – kann mit Ihren Lieblingsspielen, Fernsehsendungen usw. vollgepackt werden. und mehr. Um dies zu verhindern, müssen Sie den aktuellen Speicherstatus überwachen und unnötige Dateien von Ihrem Computer löschen. Was hat die Java-Programmierung damit zu tun? Alles! Wenn die Java-Maschine schließlich ein Objekt erstellt, weist sie diesem Objekt Speicher zu.

In einem wirklich großen Programm werden Zehntausende und Hunderttausende von Objekten erstellt, und jedem von ihnen ist ein eigener Speicher zugewiesen. Aber wie lange existieren Ihrer Meinung nach all diese Objekte? „Leben“ sie die ganze Zeit, in der unser Programm läuft? Natürlich nicht. Trotz aller Vorteile von Java-Objekten sind sie nicht unsterblich :) Objekte haben ihren eigenen Lebenszyklus. Heute machen wir eine kleine Pause beim Schreiben von Code und schauen uns diesen Prozess an :) Darüber hinaus ist es sehr wichtig für Ihr Verständnis, wie ein Programm funktioniert und wie Ressourcen verwaltet werden. Wann beginnt also das Leben eines Objekts? Wie ein Mensch – von Geburt an, also von der Schöpfung an.


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

Zunächst weist die Java Virtual Machine die erforderliche Speichermenge zu, um das Objekt zu erstellen. Dann wird ein Verweis auf diese Erinnerung erstellt. In unserem Fall heißt diese Referenz cat, damit wir den Überblick behalten können. Dann werden alle seine Variablen initialisiert, der Konstruktor aufgerufen und – ta-da! — unser frisch geprägtes Objekt lebt sein eigenes Leben :)

Da die Lebensdauer von Objekten unterschiedlich ist, können wir hier keine genauen Zahlen nennen. In jedem Fall lebt es einige Zeit im Programm und führt seine Funktionen aus. Genauer gesagt ist ein Objekt „lebendig“, solange es Hinweise darauf gibt. Sobald keine Referenzen mehr vorhanden sind, „stirbt“ das Objekt. Beispiel:


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;

   }

}

Das Lamborghini Diablo-Autoobjekt hört in der zweiten Zeile der main()Methode auf, aktiv zu sein. Es gab nur einen Verweis darauf, und dann wurde dieser Verweis auf gesetzt null. Da es keine weiteren Verweise auf den Lamborghini Diablo mehr gibt, wird der zugewiesene Speicher zu „Müll“. Dazu muss eine Referenz nicht auf null gesetzt sein:


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 haben wir ein zweites Objekt erstellt und dieses neue Objekt dann der lamborghiniReferenz zugewiesen. Jetzt Lamborghini Gallardohat das Objekt zwei Referenzen, aber das Lamborghini DiabloObjekt hat keine. Das bedeutet, dass das DiabloObjekt jetzt Müll ist. Hier kommt der in Java integrierte Mechanismus namens Garbage Collector (GC) ins Spiel.

Der Garbage Collector ist ein interner Java-Mechanismus, der dafür verantwortlich ist, Speicher freizugeben, also unnötige Objekte aus dem Speicher zu entfernen. Es gibt einen guten Grund, warum wir uns hier für das Bild eines Staubsaugerroboters entschieden haben. Schließlich funktioniert der Garbage Collector auf die gleiche Weise: Im Hintergrund „reist“ er durch Ihr Programm und sammelt praktisch ohne Ihr Zutun Müll ein. Seine Aufgabe besteht darin, Objekte zu entfernen, die nicht mehr im Programm verwendet werden.

Dadurch wird Speicherplatz im Computer für andere Objekte frei. Erinnern Sie sich, dass wir zu Beginn der Lektion gesagt haben, dass Sie im normalen Leben den Zustand Ihres Computers überwachen und unnötige Dateien löschen müssen? Nun, im Fall von Java-Objekten übernimmt der Garbage Collector dies für Sie. Der Garbage Collector wird während der Ausführung Ihres Programms wiederholt ausgeführt: Sie müssen ihn nicht explizit aufrufen oder ihm Befehle erteilen, obwohl dies technisch möglich ist. Später werden wir ausführlicher darüber sprechen und seine Arbeit genauer analysieren.

Wenn der Garbage Collector ein Objekt erreicht, ruft er unmittelbar vor der Zerstörung des Objekts eine spezielle Methode finalize()für das Objekt auf. Diese Methode kann andere vom Objekt verwendete Ressourcen freigeben. Die finalize()Methode ist Teil der ObjectKlasse. Das bedeutet, dass zusätzlich zu den Methoden equals(), hashCode()und toString(), die Sie zuvor kennengelernt haben, jedes Objekt über diese Methode verfügt. Sie unterscheidet sich von anderen Methoden dadurch, dass sie – wie soll ich das sagen – sehr kapriziös ist.

Insbesondere wird es nicht immer vor der Zerstörung eines Objekts aufgerufen. Programmieren ist ein präzises Unterfangen. Der Programmierer weist den Computer an, etwas zu tun, und der Computer führt es aus. Ich nehme an, Sie sind an dieses Verhalten bereits gewöhnt, daher kann es für Sie zunächst schwierig sein, die folgende Idee zu akzeptieren: „Vor der Zerstörung von Objekten wird die finalize()Methode der ObjectKlasse aufgerufen. Oder vielleicht wird sie auch nicht aufgerufen. Es hängt alles davon ab.“ Ihr Glück!"

Dennoch ist es wahr. finalize()Die Java-Maschine selbst bestimmt im Einzelfall , ob die Methode aufgerufen wird oder nicht . Versuchen wir beispielsweise, den folgenden Code versuchsweise auszuführen:


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

Wir erstellen ein CatObjekt und setzen dann in der nächsten Codezeile seine einzige Referenz auf null. Und das machen wir millionenfach. Wir haben die finalize()Methode explizit überschrieben, sodass sie eine Million Mal eine Zeichenfolge auf der Konsole ausgibt (einmal für jedes Mal, wenn sie ein CatObjekt zerstört). Aber nein! Um genau zu sein, lief es auf meinem Computer nur 37.346 Mal! finalize()Das heißt, nur einmal in 27 Fällen hat die auf meinem Computer installierte Java-Maschine beschlossen, die Methode aufzurufen .

In anderen Fällen erfolgte die Speicherbereinigung ohne sie. Versuchen Sie, diesen Code selbst auszuführen: Höchstwahrscheinlich erhalten Sie ein anderes Ergebnis. Wie Sie sehen, finalize()kann man kaum von einem zuverlässigen Partner sprechen :) Also ein kleiner Rat für die Zukunft: Verlassen Sie sich nicht auf die finalize()Methode, um kritische Ressourcen freizugeben. Vielleicht ruft die JVM es auf, vielleicht auch nicht. Wer weiß?

Wenn Ihr Objekt während seines Lebens einige Ressourcen enthält, die für die Leistung äußerst wichtig sind, beispielsweise eine offene Datenbankverbindung, ist es besser, eine spezielle Methode in Ihrer Klasse zu erstellen, um diese freizugeben, und sie dann explizit aufzurufen, wenn das Objekt nicht mehr aktiv ist erforderlich. Auf diese Weise können Sie sicher sein, dass die Leistung Ihres Programms nicht beeinträchtigt wird. Von Anfang an haben wir gesagt, dass die Arbeit mit dem Speicher und das Entfernen von Müll sehr wichtig ist, und das stimmt. Ein unsachgemäßer Umgang mit Ressourcen und ein Missverständnis darüber, wie unnötige Objekte bereinigt werden, können zu Speicherverlusten führen. Dies ist einer der bekanntesten Programmierfehler.

Wenn Programmierer ihren Code falsch schreiben, wird möglicherweise jedes Mal neuer Speicher für neu erstellte Objekte zugewiesen, während alte, unnötige Objekte möglicherweise nicht für die Entfernung durch den Garbage Collector verfügbar sind. Da wir einen Vergleich mit einem Roboterstaubsauger gezogen haben, stellen Sie sich vor, was passieren würde, wenn Sie vor dem Starten des Roboters Socken im ganzen Haus verteilen, eine Glasvase zerbrechen und Lego-Bausteine ​​auf dem Boden liegen lassen würden. Der Roboter wird natürlich versuchen, seine Arbeit zu erledigen, aber irgendwann bleibt er stecken.

Damit der Roboterstaubsauger ordnungsgemäß funktioniert, müssen Sie den Boden in gutem Zustand halten und alles entfernen, was der Roboter nicht bewältigen kann. Das gleiche Prinzip gilt für den Garbage Collector von Java. Wenn in einem Programm noch viele Objekte übrig sind, die nicht bereinigt werden können (z. B. eine Socke oder ein Lego-Baustein für unseren Staubsaugerroboter), geht Ihnen irgendwann der Speicher aus. Und es kann sein, dass nicht nur Ihr Programm einfriert, sondern auch jedes andere Programm, das auf dem Computer ausgeführt wird. Auch sie verfügen möglicherweise nicht über genügend Speicher.

Das müssen Sie sich nicht merken. Sie müssen nur das Prinzip dahinter verstehen, wie es funktioniert.