12 Stimmen

Wie kann ein `finalize`-Aufruf den GC / JVM unterbrechen?

Beim Untersuchen Warum verhält sich ThreadPoolExecutor anders, wenn das Java-Programm in Eclipse und von der Befehlszeile aus ausgeführt wird? Ich habe einen Test geschrieben, der einen sehr seltsamen OutOfMemoryError (max mem = 256 Mb) wirft

class A {
    byte[] buf = new byte[150_000_000];

    protected void finalize() {
        int i = 1;
    }
}

A a1 = new A();
a1 = null;
A a2 = new A();

Kommentiere int i = 1 aus und der Test funktioniert. Soweit ich verstehe, wenn finalize leer ist, ignoriert HotSpot es einfach. Aber wie kann nur ein praktisch leeres finalize-Aufruf den GC / JVM unterbrechen?

9voto

Jon Skeet Punkte 1325502

Aber wie kann nur ein leeres Finalisierungsaufruf GC / JVM unterbrechen?

Wenn ein Finalizer vorhanden ist, überleben Objekte eine Runde der Müllsammlung länger als sie es sonst tun würden (da das Objekt selbst am Leben gehalten werden muss, bis es finalisiert wird). Daher führt ein großes Objekt mit einem Finalizer zwangsläufig dazu, dass ein OutOfMemoryError in Situationen auftritt, in denen dies ohne einen Finalizer nicht der Fall wäre.

In diesem Code:

A a1 = new A();
a1 = null;
A a2 = new A();

... wird der GC in der letzten Zeile ausgelöst, um genügend Speicher zu finden, um das zweite A zuzuweisen. Leider kann er das erste A (und das Array, auf das es sich bezieht) nicht freigeben, weil der Finalizer noch nicht ausgeführt wurde. Er wartet nicht darauf, dass der Finalizer abgeschlossen ist, und versucht dann erneut, den Müll zu sammeln - er wirft einfach OutOfMemoryError.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X