2016-06-16 23 views
4

Ich hatte einen langen Artikel gelesen und finde ihn nicht. Es wurde das folgende Verhalten erläutert, bei dem ein Objekt im Bereich möglicherweise noch nicht gelöscht wurde. In jedem Fall können Sie bitte auf erklären, warum unten endet der in OutOfMemoryErrorGC löscht keine Objekte im Bereich

public static void main(String[] args) { 
    List<A> collect = null; 
    int i=0; 
    while(true){ 
     System.out.println(i++); 
     collect = IntStream.range(0, 10_00_000).mapToObj(x -> new A(x + "")).collect(Collectors.toList()); 
    } 
} 

class A{ 
    String temp; 
    A(String a){ 
     this.temp = a; 
    } 
} 

Wenn ich einen finalize in A mit einer print-Anweisung setzen, wird es nie gedruckt. Und die Instanz endet mit OOME nach wenigen Iterationen. Warum wird gc nicht vorher erstellt collect gelöscht. Und die Anzahl der Iterationen auch nicht konstant ist, es reicht von 3 sogar 100 aber letztlich nicht für -Xmx500m

Zweitens für Spaß, lief ich das obige Programm mit JIT deaktiviert -Djava.compiler=NONE. Und es läuft für immer wie erwartet. Wie beeinflusst JIT es?

PS: Wenn In eine.innerhalb meiner while-Klausel enthalten ist, wird es wie erwartet ausgeführt.

+0

versuchen Sie, den Puffer nach Ihrer System.out zu leeren. –

+0

@MarshallTigerus Das sollte keine Auswirkungen haben. By the way, es flutet von defaul; t – Jatin

+0

Es scheint das wichtigste Problem ist, dass Sie bei jeder Iteration erstellen Sie eine neue 1m Elems-Liste, und die alte Liste zu deaktivieren. Vielleicht würde man stattdessen 'collect.clear()' und dann 'collect.addAll()' aufrufen, um die – everton

Antwort

8

Ich kann Ihr Ergebnis nicht mit -Xmx500m, aber mit -Xmx200m reproduzieren. Konsequent wird das Programm fehlschlagen, wenn Sie die Methode finalize() hinzufügen, da der Finalizer die Ursache des Problems ist. Allerdings sind einige "finalized" Nachricht in meinem System gedruckt. Ohne die finalize() Methode läuft es perfekt für immer (gut, eigentlich bis ich es töte).

Es gibt kein Problem, den Platz gewöhnlicher Objekte zurückzugewinnen, aber wenn Sie eine nichttriviale Methode finalize() hinzufügen, verhindern Sie aktiv, dass die Objekte den Gültigkeitsbereich verlassen, da sie nun zur Finalisierung in die Warteschlange eingereiht werden müssen.

Während die JVM immer eine Garbage-Collection durchführt und versucht, alle nicht verwendeten Objekte freizugeben, bevor eine OutOfMemoryError geworfen wird, gibt es keine Garantie für Objekte, die in der Finalisierungswarteschlange hängen. Die Verlangsamung der Hauptaufgabe durch Deaktivieren der JIT kann in der Tat die Finalisierung ermöglichen, mehr Elemente zu verarbeiten. Denken Sie daran, dass sowohl die Hauptaufgabe als auch das Finalize-Verfahren, das auf System.out gedruckt wird, einen Synchronisierungseffekt hat, der das Timing der Verarbeitung kritisch machen kann.

Es gibt mehrere Umweltaspekte, die das Ergebnis beeinflussen können. Da es keine Garantie gibt, welcher Thread einen Finalizer ausführt, kann die Finalisierung alle nicht verwendeten CPU-Kerne verwenden (und Ihr Haupt-Thread verwendet nur einen). Auch der eigentliche Speicherbereinigungsalgorithmus (die JVM ermöglicht die Auswahl eines von mehreren verschiedenen Algorithmen) kann Auswirkungen haben.