Frage

Alle!

Ich fand seltsamen Code in LinkedBlockingQueue:

private E dequeue() {
        // assert takeLock.isHeldByCurrentThread();
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
}

Wer kann erklären, warum wir lokale Variable H brauchen? Wie kann es für GC helfen?

War es hilfreich?

Lösung

Um besser zu verstehen, wie passiert, sehen wir sehen, wie die Liste nach der Ausführung des Codes aussieht. Betrachten Sie zunächst eine erste Liste:

1 -> 2 -> 3

Dann h verweist auf head und first zu h.next:

1 -> 2 -> 3
|    |
h    first

Dann h.next verweist auf h und head verweist auf first:

1 -> 2 -> 3
|   / \
h head first

Jetzt wissen wir praktisch, dass nur aktive Referenz auf das erste Element zeigt, das für sich selbst ist (h.next = h), und wir wissen auch, dass das GC Objekte sammelt, die keine aktiven Referenzen haben. Wenn die Methode endet h existiert nur im Rahmen der Methode.

Trotzdem wurde darauf hingewiesen, und ich stimme dem zu, dass selbst mit der klassischen Dequeue -Methode (dh nur machen first zeigen auf head.next und head zeigen auf first) Es gibt keine Referenzen mehr auf den alten Kopf. In diesem Szenario bleibt der alte Kopf jedoch in Erinnerung und hat immer noch seine next Feld zeigt auf first, Während in dem Code, den Sie gepostet haben, ist das einzige, was übrig ist, ein isoliertes Objekt, das auf sich selbst zeigt. Dies kann den GC dazu bringen, schneller zu handeln.

Andere Tipps

Wenn Sie sich das JSR166 SRC ansehen, finden Sie das beleidigende Commit

http://gee.cs.oswego.edu/cgi-ner/viewcvs.cgi/jsr166/src/main/java/util/concurrent/linkedBlockingQueue.java?view=log(siehe v 1.51)

Dies zeigt, dass die Antwort in diesem Fehlerbericht liegt

http://bugs.sun.com/view_bug.do?bug_id=6805775

Die vollständige Diskussion ist in diesem Thread

http://thread.gmane.org/gmane.comp.java.jsr.166-concurrency/5758

Bei dem "Helping GC" -Bit geht es darum, Dinge zu vermeiden, die in die Begrenzung bluten.

Prost

Matt

Vielleicht etwas spät, aber die aktuelle Erklärung ist für mich völlig unbefriedigend und ich glaube, ich habe eine vernünftigere Erklärung.

Zuallererst macht jeder Java GC eine Art von einer Art von einem Wurzelsatz auf die eine oder andere Weise. Dies bedeutet, dass wir das nicht lesen werden, wenn der alte Kopf gesammelt wird next Variable sowieso - es gibt keinen Grund dazu. Somit WENN Der Kopf wird in der nächsten Iteration gesammelt, dass es keine Rolle spielt.

Das IF im obigen Satz ist der wichtige Teil hier. Der Unterschied zwischen der Einstellung neben etwas anderes spielt keine Rolle für das Sammeln von Kopf selbst, kann jedoch einen Unterschied für andere Objekte bewirken.

Nehmen wir an, ein einfacher Generations -GC: Wenn der Kopf im jungen Satz ist, wird er im nächsten GC sowieso gesammelt. Aber wenn es im alten Satz ist, wird es nur gesammelt, wenn wir einen vollen GC machen, der selten vorkommt.

Was passiert also, wenn der Kopf im alten Set ist und wir einen jungen GC machen? In diesem Fall geht die JVM davon aus, dass jedes Objekt im alten Haufen noch lebt und jede Referenz von alten zu jungen Objekten zum Wurzelsatz für den jungen GC fügt. Und genau das vermeidet die Aufgabe hier: Das Schreiben in den alten Haufen ist im Allgemeinen mit einer Schreibbarriere oder so etwas geschützt, damit die JVM solche Aufgaben erfassen und sie richtig handhaben kann - in unserem Fall wird das Objekt entfernt next aus dem Stammsatz ausgewiesen, der Konsequenzen hat.

Kurze Beispiel:

Angenommen, wir haben 1 (old) -> 2 (young) -> 3 (xx). Wenn wir jetzt 1 und 2 aus unserer Liste entfernen, können wir erwarten, dass beide Elemente vom nächsten GC gesammelt werden. Aber wenn nur ein junger GC auftritt und wir das nicht entfernt haben next Zeiger in alt, beide Elemente 1 und 2 werden nicht gesammelt. Entgegen diesem, wenn wir den Zeiger in 1 entfernt haben, wird 2 vom jungen GC gesammelt.

Hier ist ein Code -Beispiel, das die Frage veranschaulicht: http://pastebin.com/ztslpupq. Ein GC danach durchführen runWith() Und ein Heap -Dump für beide Versionen zu nehmen, sagt, dass es nur eine Elementinstanz gibt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top