Domanda

Tutti!

ho trovato strano codice 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;
}

Chi può spiegare il motivo per cui abbiamo bisogno di variabile locale h? Come può l'aiuto di GC?

È stato utile?

Soluzione

Per meglio capire cosa succede vediamo come la lista appare come dopo l'esecuzione del codice. In primo luogo prendere in considerazione un primo elenco:

1 -> 2 -> 3

punti Poi h a head e first a h.next:

1 -> 2 -> 3
|    |
h    first

punti Poi h.next a h e head punti a first:

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

Ora, in pratica sappiamo che c'è solo che punta riferimento attivo al primo elemento, che è di per sé (h.next = h), e sappiamo anche che il GC raccoglie oggetti che hanno riferimenti non più attivi, in modo che quando le estremità di metodo, il (vecchio) capo della lista ca essere raccolte in modo sicuro dal GC dal h esiste solo nell'ambito di applicazione del metodo.

Detto questo, è stato sottolineato, e sono d'accordo con questo, che anche con il metodo dequeue classico (vale a dire solo fare il punto first a head.next e head punto first) Non ci sono altri riferimenti che indicano verso la vecchia testa. Tuttavia, in questo scenario, la vecchia testa è lasciato penzoloni in memoria e ha ancora il suo campo next punta verso first, mentre nel codice che hai postato, l'unica cosa che rimane è un oggetto isolato che punta a se stesso. Questo può essere innescando il GC ad agire più rapidamente.

Altri suggerimenti

Se si guarda alla src jsr166 allora troverete l'incriminata commit

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

questo dimostra la risposta è in questo rapporto bug

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

La discussione completo è in questa discussione

http://thread.gmane.org/gmane.comp.java.jsr 0,166-concorrenza / 5758

Il bit "aiutare GC" è di evitare le cose sanguinamento in di ruolo.

Saluti

Matt

Forse un po 'in ritardo, ma la spiegazione corrente è del tutto insoddisfacente per me e penso che ho una spiegazione più sensata.

Innanzitutto GC ogni java fa qualche tipo di tracciamento da una radice impostato un modo o nell'altro. Ciò significa che se la vecchia testa viene raccolta che non leggerà la variabile next comunque - non c'è alcun motivo per farlo. Quindi IF testa viene raccolto nella successiva iterazione non importa.

L'IF nella frase sopra è la parte importante. La differenza tra l'impostazione vicino a qualcosa di diverso, non ha importanza per la raccolta di testa stessa, ma può fare la differenza per gli altri oggetti.

Supponiamo che un semplice GC generazionale: Se la testa è nei giovani insieme, che saranno raccolti nel prossimo GC comunque. Ma se è nel vecchio set saranno raccolti solo quando facciamo un GC completo che accade raramente.

Che cosa succede se la testa è nel vecchio set e facciamo un giovane GC? In questo caso la JVM presume che ogni oggetto dal vecchio mucchio è ancora vivo e aggiunge ogni riferimento da vecchi a oggetti giovani al set principale per i giovani GC. E questo è esattamente ciò che l'assegnazione evita qui: scrittura nel vecchio mucchio viene protetto con una barriera di scrittura o qualcosa in modo che la JVM può prendere tali assegnazioni e gestire correttamente - nel nostro caso si elimina la next oggetto puntato dal set radice che non avere conseguenze.

Esempio Breve:

Supponiamo di avere 1 (old) -> 2 (young) -> 3 (xx). Se togliamo 1 e 2 ora dalla nostra lista, possiamo aspettarci che entrambi gli elementi sarebbero stati raccolti dal prossimo GC. Ma se si verifica solo un giovane GC e non abbiamo rimosso il puntatore next nella vecchia, entrambi gli elementi 1 e 2 non saranno raccolti. Contrariamente a questo se abbiamo rimosso il puntatore in 1, 2 saranno raccolti dal giovane GC ..

Ecco un esempio di codice che illustra la questione: http://pastebin.com/zTsLpUpq . Esecuzione di un GC dopo runWith() e prendendo un heap dump per entrambe le versioni dice che non c'è una sola istanza dell'oggetto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top