Gibt es eine Möglichkeit, Speicher in Java freizugeben, ähnlich wie bei C free()
? Oder ist es die einzige Option, das Objekt auf null zu setzen und sich auf GC zu verlassen?
Gibt es eine Möglichkeit, Speicher in Java freizugeben, ähnlich wie bei C free()
? Oder ist es die einzige Option, das Objekt auf null zu setzen und sich auf GC zu verlassen?
Antworten:
Java verwendet verwalteten Speicher. Sie können also nur mithilfe des new
Operators Speicher zuweisen. Die einzige Möglichkeit, Speicher freizugeben, besteht darin, sich auf den Garbage Collector zu verlassen.
Dieses Whitepaper zur Speicherverwaltung (PDF) kann Ihnen helfen, zu erklären, was los ist.
Sie können auch anrufen, System.gc()
um vorzuschlagen, dass der Garbage Collector sofort ausgeführt wird. Die Java Runtime trifft jedoch die endgültige Entscheidung, nicht Ihren Code.
Gemäß der Java - Dokumentation ,
Das Aufrufen der gc-Methode legt nahe, dass die Java Virtual Machine Anstrengungen unternimmt, um nicht verwendete Objekte zu recyceln, um den aktuell belegten Speicher für eine schnelle Wiederverwendung verfügbar zu machen. Wenn die Steuerung vom Methodenaufruf zurückkehrt, hat die Java Virtual Machine nach besten Kräften versucht, Speicherplatz von allen verworfenen Objekten zurückzugewinnen.
System.gc()
völlig ignorieren .
Niemand scheint erwähnt zu haben, dass explizit Objektreferenzen festgelegt werden. Dies null
ist eine legitime Technik, um Speicher freizugeben, den Sie möglicherweise in Betracht ziehen möchten.
Angenommen, Sie haben List<String>
am Anfang einer Methode, deren Größe sehr groß wurde, eine deklariert , die jedoch nur bis zur Hälfte der Methode erforderlich war. Zu diesem Zeitpunkt können Sie die Listenreferenz so einstellen null
, dass der Garbage Collector dieses Objekt möglicherweise zurückfordern kann, bevor die Methode abgeschlossen ist (und die Referenz ohnehin nicht mehr gültig ist).
Beachten Sie, dass ich diese Technik in der Realität selten verwende, aber es lohnt sich, sie in Betracht zu ziehen, wenn Sie mit sehr großen Datenstrukturen arbeiten.
System.gc();
Führt den Garbage Collector aus.
Das Aufrufen der gc-Methode legt nahe, dass die Java Virtual Machine Anstrengungen unternimmt , um nicht verwendete Objekte zu recyceln, um den aktuell belegten Speicher für eine schnelle Wiederverwendung verfügbar zu machen. Wenn die Steuerung vom Methodenaufruf zurückkehrt, hat die Java Virtual Machine nach besten Kräften versucht, Speicherplatz von allen verworfenen Objekten zurückzugewinnen.
Nicht empfohlen.
Bearbeiten: Ich habe die ursprüngliche Antwort im Jahr 2009 geschrieben. Es ist jetzt 2015.
Müllsammler sind in den ~ 20 Jahren, in denen Java existiert, immer besser geworden. Wenn Sie den Garbage Collector manuell aufrufen, sollten Sie an dieser Stelle andere Ansätze in Betracht ziehen:
* "Ich persönlich verlasse mich auf das Nullstellen von Variablen als Platzhalter für das zukünftige ordnungsgemäße Löschen. Zum Beispiel nehme ich mir die Zeit, alle Elemente eines Arrays zu annullieren, bevor ich das Array selbst lösche (null mache)."
Dies ist nicht erforderlich. Der Java GC funktioniert so, dass er Objekte findet, auf die nicht verwiesen wird. Wenn ich also ein Objekt x mit einer Referenz (= Variable) a habe, die darauf verweist, wird es vom GC nicht gelöscht, da es eine Referenz gibt zu diesem Objekt:
a -> x
Wenn Sie a null setzen, geschieht Folgendes:
a -> null
x
X hat jetzt keinen Verweis darauf und wird gelöscht. Dasselbe passiert, wenn Sie a so einstellen, dass es auf ein anderes Objekt als x verweist.
Wenn Sie also ein Array arr haben, das auf die Objekte x, y und z verweist, und eine Variable a, die auf das Array verweist, sieht es so aus:
a -> arr -> x
-> y
-> z
Wenn Sie a null setzen, geschieht Folgendes:
a -> null
arr -> x
-> y
-> z
Der GC stellt fest, dass arr keinen Verweis darauf hat, und löscht es, wodurch Sie diese Struktur erhalten:
a -> null
x
y
z
Jetzt findet der GC x, y und z und löscht sie ebenfalls. Das Nullstellen jeder Referenz im Array macht nichts besser, es verbraucht nur CPU-Zeit und Speicherplatz im Code (das heißt, es wird nicht weiter schaden. Der GC wird weiterhin in der Lage sein, die Leistung zu erbringen, die er sollte ).
Ein triftiger Grund für den Wunsch, Speicher von einem Programm (Java oder nicht) freizugeben, besteht darin, anderen Programmen auf Betriebssystemebene mehr Speicher zur Verfügung zu stellen. Wenn meine Java-Anwendung 250 MB verwendet, möchte ich sie möglicherweise auf 1 MB reduzieren und die 249 MB für andere Apps verfügbar machen.
Um die Antwort und den Kommentar von Yiannis Xanthopoulos und Hot Licks zu erweitern (Entschuldigung, ich kann noch keinen Kommentar abgeben!), Können Sie VM-Optionen wie in diesem Beispiel festlegen:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
In meinem JDK 7 wird dann nicht verwendeter VM-Speicher freigegeben, wenn mehr als 30% des Heapspeichers nach dem GC frei werden, wenn die VM inaktiv ist. Sie müssen diese Parameter wahrscheinlich anpassen.
Obwohl ich es im folgenden Link nicht hervorgehoben gesehen habe, beachten Sie, dass einige Garbage Collectors diese Parameter möglicherweise nicht einhalten und Java standardmäßig einen davon für Sie auswählt, falls Sie mehr als einen Kern haben (daher das obige Argument UseG1GC) ).
Update: Für Java 1.8.0_73 habe ich gesehen, dass die JVM gelegentlich kleine Mengen mit den Standardeinstellungen veröffentlicht. Scheint dies nur zu tun, wenn ~ 70% des Heaps nicht verwendet werden. Ich weiß nicht, ob es aggressiver wäre, wenn das Betriebssystem nur wenig physischen Speicher hätte.
Ich habe damit experimentiert.
Es ist wahr, dass System.gc();
nur vorgeschlagen wird, den Garbage Collector auszuführen.
Wenn Sie jedoch System.gc();
nach dem Festlegen aller Verweise auf anrufen null
, werden Leistung und Speicherbelegung verbessert.
Wenn Sie wirklich einen Speicherblock zuweisen und freigeben möchten, können Sie dies mit direkten ByteBuffers tun. Es gibt sogar eine nicht tragbare Möglichkeit, den Speicher freizugeben.
Wie bereits erwähnt, bedeutet dies jedoch keine gute Idee, dies zu tun, nur weil Sie Speicher in C freigeben müssen.
Wenn Sie der Meinung sind, dass Sie wirklich einen guten kostenlosen Anwendungsfall haben (), fügen Sie ihn bitte in die Frage ein, damit wir sehen können, was Sie tun möchten. Es ist sehr wahrscheinlich, dass es einen besseren Weg gibt.
Ganz von javacoffeebreak.com/faq/faq0012.html
Ein Thread mit niedriger Priorität kümmert sich automatisch um die Speicherbereinigung für den Benutzer. Während der Leerlaufzeit kann der Thread aufgerufen werden und er kann beginnen, Speicher freizugeben, der zuvor einem Objekt in Java zugewiesen wurde. Aber keine Sorge - Ihre Objekte werden nicht gelöscht!
Wenn es keine Verweise auf ein Objekt gibt, wird es für den Garbage Collector zu einem fairen Spiel. Anstatt eine Routine aufzurufen (wie in C ++ kostenlos), weisen Sie einfach alle Verweise auf das Objekt null zu oder weisen der Referenz eine neue Klasse zu.
Beispiel:
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
Wenn Ihr Code eine große Menge an Speicher anfordern soll, möchten Sie möglicherweise den Garbage Collector auffordern, Speicherplatz zurückzugewinnen, anstatt dies als Thread mit niedriger Priorität zuzulassen. Fügen Sie dazu Ihrem Code Folgendes hinzu
System.gc();
Der Garbage Collector versucht, freien Speicherplatz zurückzugewinnen, und Ihre Anwendung kann weiterhin ausgeführt werden, wobei so viel Speicher wie möglich zurückgefordert wird (auf bestimmten Plattformen können Probleme mit der Speicherfragmentierung auftreten).
In meinem Fall möchte ich, da mein Java-Code in naher Zukunft in andere Sprachen portiert werden soll (hauptsächlich C ++), zumindest ein Lippenbekenntnis zur ordnungsgemäßen Speicherfreigabe ablegen, damit er später den Portierungsprozess erleichtert.
Ich persönlich verlasse mich darauf, Variablen als Platzhalter für das zukünftige ordnungsgemäße Löschen auf Null zu setzen. Zum Beispiel nehme ich mir die Zeit, um alle Elemente eines Arrays zu annullieren, bevor ich das Array selbst lösche (null mache).
Aber mein Fall ist sehr speziell und ich weiß, dass ich dabei Leistungstreffer mache.
* "Angenommen, Sie haben eine Liste am Anfang einer Methode deklariert, deren Größe sehr groß wurde, die jedoch erst nach der Hälfte der Methode erforderlich war. Zu diesem Zeitpunkt können Sie den Listenverweis auf null setzen damit der Garbage Collector dieses Objekt möglicherweise zurückfordern kann, bevor die Methode abgeschlossen ist (und die Referenz ohnehin außerhalb des Gültigkeitsbereichs liegt). " * *
Dies ist korrekt, aber diese Lösung ist möglicherweise nicht verallgemeinerbar. Während Sie einen List-Objektverweis auf null setzen, wird Speicher für die Garbage Collection verfügbar gemacht, gilt dies nur für ein List-Objekt primitiver Typen. Wenn das Listenobjekt stattdessen Referenztypen enthält, wird durch Setzen des Listenobjekts = null keine der in der Liste enthaltenen Referenztypen dereferenziert. In diesem Fall werden durch Festlegen des Listenobjekts = null die enthaltenen Referenztypen verwaist, deren Objekte nicht für die Speicherbereinigung verfügbar sind, es sei denn, der Algorithmus für die Speicherbereinigung ist intelligent genug, um festzustellen, ob die Objekte verwaist sind.
Obwohl Java eine automatische Speicherbereinigung bietet, möchten Sie manchmal wissen, wie groß das Objekt ist und wie viel davon noch übrig ist. Freier Speicher wird programmgesteuert verwendet, import java.lang;
und Runtime r=Runtime.getRuntime();
um Speicherwerte zu erhalten, indem Sie mem1=r.freeMemory();
den freien Speicher verwenden, rufen Sie die r.gc();
Methode und den Aufruf auffreeMemory()
Von JAVA wird empfohlen, null zuzuweisen
Von https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
Das explizite Zuweisen eines Nullwerts zu Variablen, die nicht mehr benötigt werden, hilft dem Garbage Collector, die Teile des Speichers zu identifizieren, die sicher zurückgefordert werden können. Java bietet zwar Speicherverwaltung, verhindert jedoch keine Speicherverluste oder die Verwendung übermäßiger Speichermengen.
Eine Anwendung kann Speicherlecks verursachen, indem sie keine Objektreferenzen freigibt. Dies verhindert, dass der Java-Garbage Collector diese Objekte zurückfordert, und führt dazu, dass immer mehr Speicher verwendet wird. Durch das explizite Aufheben von Verweisen auf Variablen nach ihrer Verwendung kann der Garbage Collector Speicher zurückfordern.
Eine Möglichkeit, Speicherlecks zu erkennen, besteht darin, Profiling-Tools zu verwenden und nach jeder Transaktion Speicher-Snapshots zu erstellen. Eine leckfreie Anwendung im stationären Zustand zeigt nach Speicherbereinigungen einen stabilen aktiven Heapspeicher an.