Ein ausgezeichneter Java-Programmierer muss verstehen, wie GC funktioniert, wie die Leistung von GC optimiert und wie nur eine begrenzte Interaktion mit GC durchgeführt werden kann, da einige Anwendungen hohe Leistungsanforderungen wie eingebettete Systeme, Echtzeitsysteme usw. haben, die nur sein können umfassend verbessert. In diesem Artikel wird zunächst kurz das Arbeitsprinzip von GC vorgestellt, dann eingehende Diskussionen zu mehreren wichtigen Themen von GC führt und schließlich einige Java-Programmiervorschläge vorführt, um die Leistung von Java-Programmen aus der GC-Sicht zu verbessern.
Die Grundprinzipien von GC
Die Speicherverwaltung von Java ist tatsächlich die Verwaltung von Objekten, einschließlich der Zuweisung und Veröffentlichung von Objekten.
Für Programmierer wird das neue Keyword zur Zuordnung von Objekten verwendet. .GC ist dafür verantwortlich, den Speicherraum aller /"unerreichbaren" Objekte zurückzugewinnen.
Wenn ein Programmierer ein Objekt erstellt, überwacht GC die Adresse, Größe und Verwendung des Objekts. Im Allgemeinen verwendet GC gerichtete Diagramme, um alle Objekte im Heap (Heap) aufzuzeichnen und zu verwalten (siehe Referenz 1 für Details). Auf diese Weise sind die Objekte /"erreichbar /" und welche Objekte /"nicht erreichbar /". Um jedoch sicherzustellen, dass GC auf verschiedenen Plattformen implementiert werden kann, müssen die Java -Spezifikationen jedoch nicht viele Verhaltensweisen von GC strikt. Zum Beispiel gibt es keine klaren Vorschriften zu wichtigen Fragen, wie z. B. welche Art von Recycling -Algorithmus zu verwenden ist und wann Recycling durchgeführt werden soll. Daher haben verschiedene JVM -Implementierer häufig unterschiedliche Implementierungsalgorithmen. Dies bringt auch Unsicherheit in der Entwicklung von Java -Programmierern. In diesem Artikel werden verschiedene Fragen im Zusammenhang mit der GC -Arbeit untersucht und bemüht sich, die negativen Auswirkungen dieser Unsicherheit auf Java -Programme zu verringern.
Inkrementelle GC (inkrementelle GC)
GC wird normalerweise in JVM von einem oder einer Gruppe von Prozessen implementiert. Wenn der GC lange Zeit läuft, kann der Benutzer die Pause des Java -Programms spüren. Trotzdem sollten viele Objekte recycelt werden, die nicht recycelt wurden. Daher ist es bei der Gestaltung von GC erforderlich, die Pause und die Wiederherstellungsrate abzuwägen. Eine gute GC -Implementierung ermöglicht es Benutzern, die Einstellungen zu definieren, die sie benötigen. Andere Echtzeit-Online-Spiele können langfristige Unterbrechungen des Programms nicht zulassen. Inkrementelles GC besteht darin, einen langfristigen Interrupt in viele kleine Interrupts durch einen bestimmten Recycling-Algorithmus aufzuteilen, wodurch die Auswirkungen von GC auf Benutzerprogramme verringert werden. Obwohl inkrementelle GC möglicherweise nicht so effizient wie ein regulärer GC in der Gesamtleistung ist, kann dies die maximale Pausezeit des Programms verkürzt.
Der von Sun JDK bereitgestellte Hotspot JVM kann inkrementelles GC unterstützen. Die Implementierung von Hotspot JVM Incremental GC besteht darin, den Zug -GC -Algorithmus zu verwenden. Seine grundlegende Idee ist es, alle Objekte im Haufen (hierarchisch) gemäß Erstellung und Verwendung zu gruppieren, Objekte mit einer häufigen und hochrelevanten Verwendung in eine Warteschlange zu setzen und weiter zu gruppieren, wenn das Programm die Anpassung ausführt. Wenn GC ausgeführt wird, recycelt es immer die ältesten (selten besuchten) Objekte zuerst, und wenn die gesamte Gruppe recycelbare Objekte ist, recycelt GC die gesamte Gruppe. Auf diese Weise recycelt jeder GC -Lauf nur einen bestimmten Anteil unerreichbarer Objekte, um den reibungslosen Betrieb des Programms zu gewährleisten.
Detaillierte Erläuterung der Finalize -Funktion
Finalize ist eine Methode in der Objektklasse. Da die Finalize -Funktion Kettenaufrufe nicht automatisch implementiert, müssen wir sie manuell implementieren, sodass die letzte Aussage der Finalize -Funktion normalerweise super.finalize () ist. Auf diese Weise können wir den Aufruf zur Implementierung von Finalis von unten nach oben implementieren, dh zuerst unsere eigenen Ressourcen veröffentlichen und dann die Ressourcen der übergeordneten Klasse veröffentlichen.
Nach der Java -Sprachspezifikation stellt das JVM sicher, dass dieses Objekt vor dem Aufrufen der Finalize -Funktion nicht erreichbar ist, aber die JVM garantiert nicht, dass diese Funktion aufgerufen wird. Darüber hinaus stellt die Spezifikation sicher, dass die Finalize -Funktion höchstens einmal ausgeführt wird.
Viele Java -Anfänger werden glauben, dass diese Methode dem Destruktor in C ++ ähnelt und die Veröffentlichung vieler Objekte und Ressourcen in diese Funktion einbringt. Eigentlich ist dies kein guter Weg. Es gibt drei Gründe. Zweitens kann das Objekt nach Abschluss des Abschlusses erreichbar sein, und GC muss erneut prüfen, ob das Objekt erreichbar ist. Die Verwendung von Finalize verringert daher die Leistung von GC. Drittens ist es auch ungewiss, die Zeit, in der GC -Aufrufe Finalize sind, auf diese Weise ungewiss ist.
Im Allgemeinen wird Finalize verwendet, um einige Ressourcen freizugeben, die nicht einfach zu kontrollieren sind und sehr wichtig sind, wie einige E/A -Operationen und Datenverbindungen. Die Veröffentlichung dieser Ressourcen ist für die gesamte Anwendung sehr wichtig. In diesem Fall sollten Programmierer diese Ressourcen hauptsächlich über das Programm selbst verwalten (einschließlich der Freigabe) und die Methode zur Freisetzung von Ressourcen mit der Abschlussfunktion als Ergänzung zur Bildung eines doppelten Versicherungsmanagementmechanismus ergänzen, anstatt sich ausschließlich auf die Abschluss zu verlassen, um Ressourcen zu veröffentlichen.
Hier ist ein Beispiel, um zu veranschaulichen, dass nach der Abschlussfunktion auch noch erreichbar ist.
Klasse myObject {test main; /Wiederherstellen Sie dieses Objekt, damit dieses Objekt system.out.println erreichen kann (/"Dies ist abschließend/"); // wird verwendet, um das Finale zu testen, um nur einmal auszuführen}} Klassentest {MyObject Ref; ] args) {Test = neuer Test (); .ref! = null) system.out.println (/"Mein Objekt ist noch lebt/");
Auslaufergebnisse:
Dies ist abgeschlossen
MyObject lebt noch
In diesem Beispiel sollte beachtet werden, dass das MyObject -Objekt zwar in der Finalize zu einem erreichbaren Objekt wird, das nächste Mal, wenn Sie recyceln, nicht mehr aufgerufen wird, da die Finalize -Funktion nur einmal einmal aufgerufen wird.
Wie das Programm mit GC interagiert
Java2 verbessert die Speicherverwaltungsfunktionen und fügt ein Java.lang.REF -Paket hinzu, das drei Referenzklassen definiert. Diese drei Referenzklassen sind Softretrieferenz, Schwache und Phantomreferenz. Die Referenzstärken dieser Referenzklassen sind zwischen erreichbaren und nicht erreichbaren Objekten.
Es ist auch sehr einfach, ein Referenzobjekt zu erstellen Setzen Sie die normale Referenz auf NULL. Gleichzeitig nennen wir dieses Objekt ein weiches Referenzobjekt.
Das Hauptmerkmal der weichen Referenz ist, dass es starke Zitierfunktionen hat. Diese Art des Speichers wird nur dann recycelt, wenn es nicht genügend Speicher gibt. Wenn also ausreichend Speicher vorliegt, werden sie normalerweise nicht recycelt. Darüber hinaus können diese Referenzobjekte auf NULL eingestellt werden, bevor Java die Ausnahme ausgibt Im Folgenden finden Sie die folgenden Verwendung Pseudocode für diesen Referenztyp;
// Anwendung ein Bildobjekt Bild = neuer Softreferenz (Bild); es muss neu geladen werden;
Der größte Unterschied zwischen schwachen Referenzobjekten und weichen Referenzobjekten besteht darin, dass GC einen Algorithmus verwenden muss, um zu überprüfen, ob die Soft -Referenzobjekte recycelt werden, während GC immer schwache Referenzobjekte recycycelt. Schwache Referenzobjekte sind einfacher und schneller von GC recycelt. Obwohl GC beim Laufen schwache Objekte recyceln muss, erfordert eine Gruppe schwacher Objekte mit komplexen Beziehungen häufig mehrere GC -Läufe. In Kartenstrukturen werden häufig schwache Referenzobjekte verwendet, um Objekte mit großen Datenvolumina zu beziehen.
Phantomreferenzen sind weniger nützlich und werden hauptsächlich verwendet, um die Verwendung von Finalize -Funktionen zu unterstützen. Phantomobjekte beziehen sich auf einige Objekte, die die Finalize -Funktion abgeschlossen haben und nicht erreichbare Objekte sind, sie wurden jedoch von GC nicht recycelt. Diese Art von Objekt kann bei einigen späteren Recyclingarbeiten die Flexibilität des Ressourcenrecycling -Mechanismus verbessern, indem wir die Referenz -Clear () -Methode überschreiben.
Einige Java -Codierungsvorschläge
Nach dem Arbeitsprinzip von GC können wir einige Fähigkeiten und Methoden einsetzen, um GC effizienter und mehr den Anforderungen der Anwendung zu entsprechen. Hier sind einige Vorschläge für die Programmierung.
1. Der grundlegendste Vorschlag besteht darin, die Referenzen nutzloser Objekte so bald wie möglich freizugeben. Wenn die meisten Programmierer temporäre Variablen verwenden, setzen sie die Referenzvariable automatisch auf Null, nachdem wir die aktive Domäne (Umfang) beendet haben. Diagramme usw. haben eine komplexe Beziehung zwischen diesen Objekten. Für solche Objekte sind GC sie im Allgemeinen weniger effizient. Wenn das Programm es erlaubt, weisen Sie Null das nicht verwendete Referenzobjekt so schnell wie möglich zu. [Seite]
2. Versuchen Sie, die endgültige Funktion so wenig wie möglich zu verwenden. Die Finalize -Funktion bietet Java die Möglichkeit, den Programmierern die Möglichkeit zu geben, Objekte oder Ressourcen freizusetzen. Es wird jedoch die Arbeitsbelastung von GC erhöhen. Versuchen Sie daher, die Finanzierung so wenig wie möglich zu verwenden, um Ressourcen zu recyceln.
3. Wenn Sie häufig verwendete Bilder verwenden müssen, können Sie den Soft -Anwendungstyp verwenden. Es kann das Bild so weit wie möglich im Speicher speichern, damit das Programm angerufen werden kann, ohne auszuschalten.
V. Achten Sie auch auf einige globale Variablen sowie einige statische Variablen. Diese Variablen verursachen tendenziell leicht baumelnde Referenzen und verursachen Speicherabfälle.
5. Wenn das Programm eine bestimmte Wartezeit hat, kann der Programmierer das System manuell ausführen. Die Verwendung von inkrementellem GC kann die Pausezeit von Java -Programmen verkürzen.