OutOfMemoryError



  • Hallo zusammen,

    gibt es die Möglichkeit bevor ein OutOfMemoryError geworden wird,
    noch wieder cached Objects freizugeben?
    Wird vorher irgendeine Methode aufgerufen, für deren Aufruf man sich
    registrieren kann, so dass man selbst was behandeln kann?

    Gruß,
    CSpille



  • Nein, für sowas gibt es weak references.



  • Optimizer schrieb:

    Nein, für sowas gibt es weak references.

    Huh? Inwiefern kann man die für soetwas einsetzen?



  • Ich hab CSpille so verstanden: Bevor er keinen Speicher mehr hat, will er schnell ein paar Objekte nicht mehr referenzieren, damit der GC sie frisst. Für sowas sind weak references doch da. Man kann das Objekt weiterhin referenziert haben, aber wenn der Speicher dann knapp wird und der GC ne full collection machen muss, frisst er das Objekt trotzdem und setzt die Referenz auf null.



  • Naja, ehrlich gesagt bin ich mir über den Einsatzzeck dieser ganzen References nicht so ganz klar. Es gib da ja mehrere: WeakReferences, SoftReferences und PhantomReferences.

    Die WeakReference kenne ich im Prinzip nur im Zusammenhang mit einer WeakHashMap. Da werden solche Referenzen für die Schlüssel verwendet. Die Funktionsweise von diesen Referenzen ist AFAIK so, dass sie selbst nicht dafür sorgen, dass das entsprechende Objekt nicht vom GC eingesammelt wird. Das heißt, man kann diese Referenzen nutzen, wenn man an einer Stelle auf ein bestimmtes Objekt zugreifen können will, aber nur so lange, wie es auch noch an einer anderen Stelle referenziert wird. Ein ausschließlich schwach referenziertes Objekt wird AFAIK nicht erst einer Full-Collection eingesammelt, sondern kann immer vom GC eingesammelt werden. Insofern kann man hiermit nicht so eine Art Puffer bauen, der einem in Problemfällen nochmal ein bischen Speicher gibt bzw. eine Art Warner, der gelöscht wird, wenn der Speicher knapp wird.

    AFAIK gibt es keine Möglichkeit, im Vorhinein systematisch auf einen OutOfMemoryError zu reagieren. Das einzige, was man da IMHO machen könnte, wäre, bei bestimmten Speicherfressenden Algorithmen explizit vorher zu testen, wieviel Speicher noch zur Verfügung steht und ob der Algorithmus wohl mehr benötigt.

    Eine Sache sollte aber in jedem Fall klar sein und ist vermutlich auch klar: Man sollte einen OutOfMemoryError NIE fangen, obwohl das geht. Das ist ein "Error" und keine "Exception". "Error" bedeutet hierbei, dass die JVM dadurch in einen undefinierten Zustand übergeht und damit sollte man in keinem Fall ein Programm weiterlaufen lassen.



  • Gregor schrieb:

    Naja, ehrlich gesagt bin ich mir über den Einsatzzeck dieser ganzen References nicht so ganz klar.

    IMHO ist es für so etwas gut, was CSpille will.

    Die Funktionsweise von diesen Referenzen ist AFAIK so, dass sie selbst nicht dafür sorgen, dass das entsprechende Objekt nicht vom GC eingesammelt wird.

    Ja richtig, das ist doch super für diese Problemstellung, oder? Stell dir mal vor, ich cache den lesenden Zugriff auf ein Dateisystem, will aber die Cache-Größe einigermaßen gering halten. Wie du sicher weißt, sind Festplattenzugriffe in ms zu messen, wenn das während einer heißen 3D-Action ist, ist das mein Tod (oder nimm eine Datenstruktur, die aufwändig aufzubauen ist). Deshalb referenziere ich alle einmal ausgelesenen Objekte mit schwachen Referenzen und vielleicht ist das Objekt noch da, wenn ich es wieder mal brauche, vielleicht aber auch nicht. Wenn ich inzwischen viele andere Teile der Karte nachgeladen habe, ist es wahrscheinlich, dass der GC schon was freimachen musste. Ich kriege aber auf jeden Fall nie wegen dem Caching-System einen OutOfMemoryError. War das nicht das, was CSpille wollte?

    Das heißt, man kann diese Referenzen nutzen, wenn man an einer Stelle auf ein bestimmtes Objekt zugreifen können will, aber nur so lange, wie es auch noch an einer anderen Stelle referenziert wird. Ein ausschließlich schwach referenziertes Objekt wird AFAIK nicht erst einer Full-Collection eingesammelt, sondern kann immer vom GC eingesammelt werden. Insofern kann man hiermit nicht so eine Art Puffer bauen, der einem in Problemfällen nochmal ein bischen Speicher gibt bzw. eine Art Warner, der gelöscht wird, wenn der Speicher knapp wird.

    Es kann auch nur schwach referenziert werden, wie beim Beispiel mit dem Dateisystem-Cache. In diesem Fall lebt das Objekt je nach Speicherbedarf unterschiedlich lang. Wenn es einmal in der tenured generation, oder wie das beim Java-GC heißt, ist, dann kann es ziemlich lange noch verfügbar sein. Ich krieg oft bis zu 200 kleine GCs, bevor mal ein großer kommt. Als "Reserve" bei Speicherknappheit sollte man die weak references natürlich nicht verwenden.

    Eine Sache sollte aber in jedem Fall klar sein und ist vermutlich auch klar: Man sollte einen OutOfMemoryError NIE fangen, obwohl das geht. Das ist ein "Error" und keine "Exception". "Error" bedeutet hierbei, dass die JVM dadurch in einen undefinierten Zustand übergeht und damit sollte man in keinem Fall ein Programm weiterlaufen lassen.

    Sehe ich genauso. 🙂



  • Danke Jungs...

    Das mit den References ist genau das, was ich brauche...

    Ich kann mir ja auch in ne Reference nen Objekt packen, das beim destroy
    erstnoch etwas anderes aufräumt oder spricht da was gegen?

    Gruß,
    CSpille



  • Was für ein destroy? Du kriegst keinen Hinweis, wenn ein Objekt vom GC aufgeräumt wird und es gibt hierfür auch keine Art Destruktor. Vielleicht denkst du zu sehr in

    CSpille schrieb:

    Java ist der kleine behinderte Bruder von C++

    Du musst umdenken. Du räumst nicht selber den Speicher auf, du sagst nur den GC, was er nicht wegräumen darf, indem du die gewünschen Objekte referenzierst. Und mit schwachen Referenzen kannst du sagen "räum' es ruhig weg wenn du brauchst, aber solange du es nicht wegräumst, will ich es noch benutzen können".



  • Hallo Optimizer,

    er ruft ja vor dem Zerstören eines Objectes die finalize Methode auf:

    public class CleanUp {
    
    	protected void finalize() throws Throwable {
    		// Clean up
    		super.finalize();
    	}
    }
    
    CleanUp cu = new CleanUp();
    		SoftReference reference = new SoftReference(cu);
    		cu = null;
    		// und die reference irgendwo verankern
    		// nach dem Sie zerstört wurde muss sie natürlich wieder angelegt werden
    

    Ich meine das etwa so...

    Gruß,
    CSpille



  • finalize() ist gedacht um Resourcen, die nicht auf dem GC-Heap liegen, freizugeben. z.B. um ne Socket-Verbindung zu schließen. Wann und wo (welcher Thread) und ob überhaupt finalize() aufgerufen wird, darüber hast du keine Garantien. Das ist also ein denkbar schlechter Ort, um ein OutOfMemory verhindern zu wollen.
    Außerdem musst du schwache Referenzen nicht selber auf null setzen, die ignoriert der GC bei der Mark-Phase sowieso und setzt sie für dich auf null, wenn er das Objekt sammelt. Du kannst also das killen dieses Objekts nicht auf diese Weise beschleunigen. Ganz im Gegenteil verlangsamst du damit die garbage collection der Objekte, die die finalize()-Methode überschrieben haben, weil sie 2mal collected werden müssen.




Anmelden zum Antworten