Ich weiß, dass die Speicherbereinigung in Java automatisiert ist. Aber ich habe verstanden, dass, wenn Sie System.gc()
Ihren Code aufrufen , die JVM möglicherweise entscheidet, an diesem Punkt eine Speicherbereinigung durchzuführen oder nicht. Wie funktioniert das genau? Auf welcher Basis / auf welchen Parametern entscheidet sich die JVM genau, einen GC durchzuführen (oder nicht), wenn sie sieht System.gc()
?
Gibt es Beispiele, in welchem Fall es eine gute Idee ist, dies in Ihren Code aufzunehmen?
java
garbage-collection
Michael
quelle
quelle
Antworten:
In der Praxis wird normalerweise eine Speicherbereinigung durchgeführt. Die Antwort hängt von vielen Faktoren ab, z. B. von der JVM, auf der Sie ausgeführt werden, in welchem Modus und in welchem Garbage Collection-Algorithmus.
Ich würde mich in Ihrem Code nicht darauf verlassen. Wenn die JVM im Begriff ist, einen OutOfMemoryError auszulösen, wird der Aufruf von System.gc () ihn nicht stoppen, da der Garbage Collector versucht, so viel wie möglich freizugeben, bevor es zu diesem Extrem kommt. Das einzige Mal, dass ich es in der Praxis gesehen habe, ist in IDEs, wo es an eine Schaltfläche angehängt ist, auf die ein Benutzer klicken kann, aber selbst dort ist es nicht besonders nützlich.
quelle
System.gc()
in einem Ladebildschirm für ein Videospiel verwenden. Zu diesem Zeitpunkt wäre es mir eigentlich egal, ob der Anruf alles löschte, was er konnte, oder überhaupt nichts tat. Ich würde es jedoch vorziehen, dass es "Aufwand für das Recycling nicht verwendeter Objekte" während des Ladebildschirms und nicht während des Spiels erfordert.Das einzige Beispiel, an das ich denken kann, wo es sinnvoll ist, System.gc () aufzurufen, ist die Profilerstellung einer Anwendung, um nach möglichen Speicherlecks zu suchen. Ich glaube, die Profiler rufen diese Methode auf, bevor sie einen Speicherschnappschuss machen.
quelle
Die Java-Sprachspezifikation garantiert nicht, dass die JVM beim Aufruf einen GC startet
System.gc()
. Dies ist der Grund dafür, dass "zu diesem Zeitpunkt möglicherweise eine GC durchgeführt wird oder nicht".Wenn Sie sich nun den OpenJDK-Quellcode ansehen , der das Rückgrat von Oracle JVM darstellt, werden Sie feststellen, dass ein Aufruf von
System.gc()
einen GC-Zyklus startet. Wenn Sie eine andere JVM wie J9 verwenden, müssen Sie deren Dokumentation überprüfen, um die Antwort zu finden. Zum Beispiel verfügt Azul's JVM über einen Garbage Collector, der kontinuierlich ausgeführt wird, sodass ein Aufruf vonSystem.gc()
nichts zu tun hatEinige andere Antworten erwähnen das Starten eines GC in JConsole oder VisualVM. Grundsätzlich führen diese Tools einen Fernanruf an
System.gc()
.Normalerweise möchten Sie keinen Garbage Collection-Zyklus mit Ihrem Code starten, da dies die Semantik Ihrer Anwendung beeinträchtigt. Ihre Anwendung erledigt einige geschäftliche Aufgaben, die JVM kümmert sich um die Speicherverwaltung. Sie sollten diese Bedenken getrennt halten (lassen Sie Ihre Anwendung keine Speicherverwaltung durchführen, sondern konzentrieren Sie sich auf das Geschäft).
Es gibt jedoch nur wenige Fälle, in denen ein Anruf bei
System.gc()
verständlich sein könnte. Betrachten Sie beispielsweise Mikrobenchmarks. Niemand möchte, dass ein GC-Zyklus mitten in einem Mikrobenchmark stattfindet. Sie können also zwischen jeder Messung einen GC-Zyklus auslösen, um sicherzustellen, dass jede Messung mit einem leeren Heap beginnt.quelle
Sie haben keine Kontrolle über GC in Java - die VM entscheidet. Ich bin noch nie auf einen Fall gestoßen, in dem
System.gc()
es nötig ist . Da einSystem.gc()
Aufruf lediglich EMPFIEHLT, dass die VM eine Garbage Collection und auch eine FULL Garbage Collection (alte und neue Generationen in einem Heap mit mehreren Generationen) durchführt, kann dies dazu führen, dass MEHR CPU-Zyklen verbraucht werden als erforderlich.In einigen Fällen kann es sinnvoll sein, der VM vorzuschlagen, JETZT eine vollständige Erfassung durchzuführen, da Sie möglicherweise wissen, dass die Anwendung die nächsten Minuten im Leerlauf bleibt, bevor schweres Heben auftritt. Zum Beispiel direkt nach der Initialisierung vieler temporärer Objekte während des Starts der Anwendung (dh ich habe gerade eine TONNE Informationen zwischengespeichert und weiß, dass ich für eine Minute oder so nicht viel Aktivität bekomme). Denken Sie an eine IDE wie das Starten von Eclipse - die Initialisierung ist sehr umfangreich. Daher ist es möglicherweise unmittelbar nach der Initialisierung sinnvoll, an diesem Punkt eine vollständige GC durchzuführen.
quelle
Sie müssen sehr vorsichtig sein, wenn Sie anrufen
System.gc()
. Durch das Aufrufen kann Ihre Anwendung unnötige Leistungsprobleme verursachen, und es wird nicht garantiert, dass tatsächlich eine Sammlung ausgeführt wird. Es ist tatsächlich möglich, explizitSystem.gc()
über das Java-Argument zu deaktivieren-XX:+DisableExplicitGC
.Ich würde dringend empfehlen, die bei Java HotSpot Garbage Collection verfügbaren Dokumente zu lesen, um detailliertere Informationen zur Garbage Collection zu erhalten.
quelle
System.gc()
wird von der VM implementiert und ist implementierungsspezifisch. Der Implementierer könnte zum Beispiel einfach zurückkehren und nichts tun.Wenn Sie eine manuelle Sammlung erstellen möchten, können Sie dies möglicherweise nur tun, wenn Sie eine große Sammlung mit vielen kleineren Sammlungen verlassen -
Map<String,<LinkedList>>
beispielsweise eine - und dann und möchten versuchen, den Perf-Hit zu erzielen dort, aber zum größten Teil sollten Sie sich darüber keine Sorgen machen. Der GC weiß es leider die meiste Zeit besser als Sie.quelle
Wenn Sie direkte Speicherpuffer verwenden, führt die JVM den GC nicht für Sie aus, selbst wenn Ihnen der direkte Speicher ausgeht.
Wenn Sie aufrufen
ByteBuffer.allocateDirect()
und einen OutOfMemoryError erhalten, können Sie feststellen, dass dieser Aufruf in Ordnung ist, nachdem Sie einen GC manuell ausgelöst haben.quelle
Cleaners
die der direkte Speicher verwendet wird. dh es wird vom Finalisator-Thread nicht freigegeben, da dies zu langsam sein kann. Trotzdem ist es möglich, ein OOME zu erhalten, wenn Sie besonders schnell direkte Speicherbereiche erstellen. Die Lösung besteht darin, dies nicht zu tun und Ihre direkten Speicherbereiche wiederzuverwenden, wo Sie können.Die meisten JVMs starten einen GC (abhängig vom Schalter -XX: DiableExplicitGC und -XX: + ExplicitGCInvokesConcurrent). Die Spezifikation ist jedoch weniger genau definiert, um später bessere Implementierungen zu ermöglichen.
Die Spezifikation muss geklärt werden: Fehler # 6668279: (spec) System.gc () sollte anzeigen, dass wir die Verwendung nicht empfehlen und das Verhalten nicht garantieren
Intern wird die gc-Methode von RMI und NIO verwendet und erfordert eine synchrone Ausführung. Dies wird derzeit diskutiert:
Fehler # 5025281: Erlaube System.gc (), gleichzeitige (nicht die Welt stoppende) vollständige Sammlungen auszulösen
quelle
Garbage Collection
ist gut inJava
, wenn wir in Java codierte Software in Desktop / Laptop / Server ausführen. Sie können anrufenSystem.gc()
oderRuntime.getRuntime().gc()
inJava
.Beachten Sie nur, dass keiner dieser Anrufe garantiert etwas bewirkt. Sie sind nur ein Vorschlag für das JVM, den Garbage Collector auszuführen. Es liegt an der JVM, ob sie den GC ausführt oder nicht. Also, kurze Antwort: Wir wissen nicht, wann es läuft. Längere Antwort: JVM würde gc ausführen, wenn es Zeit dafür hat.
Ich glaube, das gilt auch für Android. Dies kann jedoch Ihr System verlangsamen.
quelle
Normalerweise führt die VM vor dem Auslösen einer OutOfMemoryException automatisch eine Garbage Collection durch. Das Hinzufügen eines expliziten Aufrufs sollte daher nicht helfen, es sei denn, dies verschiebt den Leistungseinbruch möglicherweise auf einen früheren Zeitpunkt.
Ich glaube jedoch, dass ich auf einen Fall gestoßen bin, in dem dies relevant sein könnte. Ich bin mir jedoch nicht sicher, da ich noch nicht getestet habe, ob es irgendwelche Auswirkungen hat:
Wenn Sie eine Datei im Speicher abbilden, löst der Aufruf von map () meiner Meinung nach eine IOException aus, wenn kein ausreichend großer Speicherblock verfügbar ist. Eine Garbage Collection kurz vor der map () - Datei könnte helfen, dies zu verhindern, denke ich. Was denken Sie?
quelle
Wir können niemals die Müllabfuhr erzwingen. System.gc schlägt vm nur für die Speicherbereinigung vor. Allerdings weiß niemand wirklich, wann der Mechanismus ausgeführt wird. Dies entspricht den JSR-Spezifikationen.
quelle
Es gibt viel zu sagen, wenn man sich die Zeit nimmt, um die verschiedenen Einstellungen für die Speicherbereinigung zu testen, aber wie oben erwähnt, ist dies normalerweise nicht sinnvoll.
Ich arbeite derzeit an einem Projekt mit einer speicherbeschränkten Umgebung und relativ großen Datenmengen. Es gibt einige große Datenmengen, die meine Umgebung an ihre Grenzen bringen, und obwohl ich die Speichernutzung so reduzieren konnte dass es theoretisch gut funktionieren sollte, ich würde immer noch Heap-Space-Fehler bekommen - die ausführlichen GC-Optionen zeigten mir, dass es versuchte, Müll zu sammeln, aber ohne Erfolg. Im Debugger konnte ich System.gc () ausführen und sicher war "viel" Speicher verfügbar ... nicht viel Extra, aber genug.
Folglich ruft meine Anwendung System.gc () nur dann auf, wenn sie in das Codesegment eingibt, in dem große Puffer zugewiesen werden, die für die Verarbeitung der Daten erforderlich sind, und ein Test des verfügbaren freien Speichers zeigt an, dass dies nicht der Fall ist garantiert, um es zu haben. Insbesondere betrachte ich eine 1-GB-Umgebung, in der mindestens 300 MB mit statischen Daten belegt sind, wobei der Großteil der nicht statischen Daten ausführungsbezogen ist, es sei denn, die verarbeiteten Daten sind mindestens 100 bis 200 MB groß die Quelle. Dies alles ist Teil eines automatischen Datenkonvertierungsprozesses, sodass die Daten auf lange Sicht nur für relativ kurze Zeiträume vorhanden sind.
Obwohl Informationen über die verschiedenen Optionen zum Optimieren des Garbage Collectors verfügbar sind, scheint dies leider weitgehend ein experimenteller Prozess zu sein, und die Einzelheiten der unteren Ebene, die zum Verständnis des Umgangs mit diesen spezifischen Situationen erforderlich sind, sind nicht leicht zu erhalten.
Obwohl ich System.gc () verwende, habe ich trotzdem die Verwendung von Befehlszeilenparametern fortgesetzt und es geschafft, die Gesamtverarbeitungszeit meiner Anwendung um einen relativ erheblichen Betrag zu verbessern, obwohl ich nicht in der Lage war, darüber hinwegzukommen Stolperstein durch die Arbeit mit den größeren Datenblöcken. Davon abgesehen ist System.gc () ein Tool ... ein sehr unzuverlässiges Tool, und wenn Sie nicht vorsichtig sind, wie Sie es verwenden, werden Sie sich wünschen, dass es nicht öfter funktioniert als nicht.
quelle
Wenn Sie wissen möchten, ob Ihr
System.gc()
aufgerufen wird, können Sie mit dem neuen Java 7-Update 4 eine Benachrichtigung erhalten, wenn die JVM die Garbage Collection durchführt.Ich bin nicht 100% sicher , dass die GarbageCollectorMXBean Klasse war einleitet in Java 7 Update 4 aber, weil ich es nicht in den Release Notes finden konnte, aber ich fand die Informationen in der javaperformancetuning .com - Website
quelle
Ich kann mir kein konkretes Beispiel vorstellen, wenn es gut ist, explizite GC auszuführen.
Im Allgemeinen kann das Ausführen eines expliziten GC mehr Schaden als Nutzen verursachen, da ein expliziter GC eine vollständige Sammlung auslöst, die erheblich länger dauert, wenn jedes Objekt durchlaufen wird. Wenn dieser explizite gc wiederholt aufgerufen wird, kann dies leicht zu einer langsamen Anwendung führen, da viel Zeit für die Ausführung vollständiger GCs aufgewendet wird.
Wenn Sie alternativ mit einem Heap-Analysator über den Heap gehen und vermuten, dass eine Bibliothekskomponente explizite GCs aufruft, können Sie diese deaktivieren, indem Sie den JVM-Parametern Folgendes hinzufügen: gc = -XX: + DisableExplicitGC.
quelle
Accroding zu Denken in Java von Bruce Eckel, ein Anwendungsfall für expliziten System.gc () Aufruf ist , wenn Sie Kraft Abschluss mögen, dh den Aufruf Finalisierung Methode.
quelle
Während system.gc funktioniert, wird die Welt gestoppt: Alle Antworten werden gestoppt, sodass der Garbage Collector jedes Objekt scannen kann, um zu überprüfen, ob es gelöscht werden muss. Wenn es sich bei der Anwendung um ein Webprojekt handelt, werden alle Anforderungen gestoppt, bis gc abgeschlossen ist. Dies führt dazu, dass Ihr Webprojekt nicht in einem Monent arbeiten kann.
quelle