AFAIK, die JVM-Spezifikation (in englischer Sprache) erwähnt nicht, wann genau ein Objekt (oder ein Wert) gelöscht werden soll, und überlässt dies der Implementierung (ebenfalls für R5RS ). Irgendwie wird ein Garbage Collector benötigt oder vorgeschlagen, die Details bleiben jedoch der Implementierung überlassen. Und ebenfalls für die Java-Spezifikation.
Denken Sie daran , dass Programmiersprachen sind Spezifikationen (von Syntax , Semantik , etc ...), keine Software - Implementierungen. Eine Sprache wie Java (oder ihre JVM) hat viele Implementierungen. Die Spezifikation ist veröffentlicht , herunterladbar (damit Sie sie studieren können) und in englischer Sprache verfasst. §2.5.3 Heap der JVM-Spezifikation erwähnt einen Garbage Collector:
Der Heapspeicher für Objekte wird von einem automatischen Speicherverwaltungssystem (Garbage Collector) zurückgefordert. Objekte werden niemals explizit freigegeben. Die Java Virtual Machine setzt keinen bestimmten Typ eines automatischen Speicherverwaltungssystems voraus
(Der Schwerpunkt liegt bei mir. Die BTW-Finalisierung wird in §12.6 der Java-Spezifikation und ein Speichermodell in §17.4 der Java-Spezifikation erwähnt.)
(In Java) sollte es Ihnen also egal sein, wann ein Objekt gelöscht wird , und Sie könnten so codieren, als ob dies nicht der Fall wäre (indem Sie in einer Abstraktion argumentieren, in der Sie dies ignorieren). Natürlich müssen Sie sich um den Speicherverbrauch und den Satz lebender Objekte kümmern, was eine andere Frage ist. In einigen einfachen Fällen (denken Sie an ein "Hallo-Welt" -Programm) können Sie nachweisen - oder sich selbst davon überzeugen -, dass der zugewiesene Speicher ziemlich klein ist (z. B. weniger als ein Gigabyte), und dann interessiert Sie das überhaupt nicht Löschen einzelner Objekte. In mehr Fällen können Sie sich davon überzeugen, dass die lebenden Objekte(oder erreichbare, was eine Menge ist, die es einfacher macht, über lebende nachzudenken) Überschreiten Sie niemals eine vernünftige Grenze (und dann verlassen Sie sich auf GC, aber es ist Ihnen egal, wie und wann die Garbage Collection stattfindet). Lesen Sie mehr über Raumkomplexität .
Ich vermute, dass bei einigen JVM- Implementierungen, in denen ein kurzlebiges Java-Programm wie ein Hello World-Programm ausgeführt wird, der Garbage Collector überhaupt nicht ausgelöst wird und keine Löschung erfolgt. AFAIU, ein solches Verhalten entspricht den zahlreichen Java-Spezifikationen.
Die meisten JVM-Implementierungen verwenden generative Kopiertechniken (zumindest für die meisten Java-Objekte, die keine Finalisierung oder schwachen Referenzen verwenden) . Die Finalisierung kann nicht garantiert in kurzer Zeit erfolgen und kann verschoben werden. Dies ist nur eine hilfreiche Funktion, die Ihr Code nicht sollte davon abhängen, inwieweit der Gedanke, ein einzelnes Objekt zu löschen, keinen Sinn ergibt (da ein großer Block von Speicherbereichen für viele Objekte, möglicherweise mehrere Megabyte auf einmal, auf einmal freigegeben wird).
Wenn die JVM-Spezifikation vorschreibt, dass jedes Objekt so schnell wie möglich genau gelöscht wird (oder einfach die Objektlöschung stärker einschränkt), sind effiziente generative GC-Techniken verboten, und die Designer von Java und der JVM haben dies mit Bedacht vermieden.
Übrigens könnte es sein, dass eine naive JVM, die niemals Objekte löscht und keinen Speicher freigibt, den Spezifikationen (dem Buchstaben, nicht dem Geist) entspricht und mit Sicherheit in der Lage ist, in der Praxis eine Hallo-Welt-Sache auszuführen (beachten Sie, dass die meisten winzige und kurzlebige Java-Programme belegen wahrscheinlich nicht mehr als ein paar Gigabyte Speicher. Natürlich ist eine solche JVM nicht erwähnenswert und nur eine Spielzeugsache (wie diese Implementierung malloc
für C). Weitere Informationen finden Sie im Epsilon NoOp GC . Real-Life-JVMs sind sehr komplexe Softwareteile und kombinieren verschiedene Techniken zur Garbage Collection.
Auch Java ist nicht die gleiche wie die JVM, und Sie haben Java - Implementierungen ohne die JVM ausgeführt wird (zB Voraus-Zeit Java - Compiler, Android Runtime ). In einigen Fällen (meistens akademischen) können Sie sich vorstellen (sogenannte "Kompilierungszeit-Garbage-Collection" -Techniken), dass ein Java-Programm zur Laufzeit keine Zuordnung oder Löschung vornimmt (z. B. weil der optimierende Compiler klug genug war, nur die zu verwenden) Aufrufstapel und automatische Variablen ).
Warum werden Java-Objekte nicht sofort gelöscht, nachdem sie nicht mehr referenziert wurden?
Weil die Java- und JVM-Spezifikationen dies nicht erfordern.
Lesen Sie das GC-Handbuch (und die JVM-Spezifikation ). Beachten Sie, dass es sich bei einem Objekt um eine (nicht modulare) Ganzprogramm-Eigenschaft handelt, die lebendig ist (oder für zukünftige Berechnungen nützlich ist).
Objective-C bevorzugt einen Referenzzählansatz für die Speicherverwaltung . Und das hat auch Fallstricke (z. B. muss sich der Objective-C- Programmierer um Zirkelverweise kümmern, indem er schwache Verweise expliziert, aber eine JVM verarbeitet Zirkelverweise in der Praxis gut, ohne dass der Java-Programmierer darauf achten muss).
Es gibt kein Patentrezept für die Programmierung und das Design von Programmiersprachen (seien Sie sich des Halteproblems bewusst , ein nützliches lebendes Objekt zu sein, ist im Allgemeinen unentscheidbar ).
Sie könnten auch SICP , Programmiersprache Pragmatik , das Drachenbuch , Lisp in kleinen Stücken und Betriebssysteme lesen : Drei einfache Stücke . Es geht nicht um Java, aber es wird Ihnen den Kopf öffnen und Ihnen helfen, zu verstehen, was eine JVM tun sollte und wie sie (mit anderen Komponenten) auf Ihrem Computer praktisch funktionieren könnte. Sie könnten auch viele Monate (oder mehrere Jahre) damit verbringen, den komplexen Quellcode bestehender Open-Source- JVM-Implementierungen (wie OpenJDK mit mehreren Millionen Quellcodezeilen) zu untersuchen.