2012-09-14 20 views
13

Quando uso un dovrei chiamare sempre remove() quando ho finito o quando faccio il set il vecchio valore è sostituito comunque così remove è ridondante?Threadlocal remove?

risposta

12

set sostituisce sempre il vecchio valore.

Questo è vero per

  • Calendar.set() e Date.set()
  • BitSet.set()
  • List.set()
  • setter

Vuoi dire senza rimuovere non sarà GCed?

Non sarà rimosso finché il filo non muore. Non sparirà su di te senza che tu chiami remove()

Se questa è una perdita di memoria o meno dipende dal tuo programma. Dovresti creare molti thread con oggetti locali con thread di grandi dimensioni che non ti servivano per qualche motivo per farlo. per esempio. 1000 thread con un oggetto da 1 KB possono perdere fino a 1 MB, ma questo suggerisce un problema di progettazione se si sta facendo questo genere di cose.


L'unico posto dove si può verificare una perdita di memoria è.

for (int i = 0; ; i++) { 
    // don't subclass Thread. 
    new Thread() { 
     // this is somewhat pointless as you are defining a ThreadLocal per thread. 
     final ThreadLocal<Object> tlObject = new ThreadLocal<Object>() { 
     }; 

     public void run() { 
      tlObject.set(new byte[8 * 1024 * 1024]); 
     } 
    }.start(); 
    Thread.sleep(1); 
    if (i % 1000 == 0) { 
     System.gc(); 
     System.out.println(i); 
    } 
} 

con -verbosegc stampe.

[Full GC 213548K->49484K(3832192K), 0.0334194 secs] 
39000 
[GC 2786060K->82412K(3836864K), 0.0132035 secs] 
[GC 2815569K->107052K(3836544K), 0.0212252 secs] 
[GC 2836162K->131628K(3837824K), 0.0199268 secs] 
[GC 2867613K->156204K(3837568K), 0.0209828 secs] 
[GC 2886894K->180780K(3838272K), 0.0191244 secs] 
[GC 2911942K->205356K(3838080K), 0.0187482 secs] 
[GC 421535K->229932K(3838208K), 0.0192605 secs] 
[Full GC 229932K->49484K(3838208K), 0.0344509 secs] 
40000 

Nota: la dimensione dopo un GC completo è lo stesso 49484K

Nel caso di cui sopra si avrà un ThreadLocal che si riferisce alla discussione che si riferisce alla ThreadLocal. Tuttavia, poiché il thread è morto, non causa una perdita di memoria perché diventa un oggetto di interesse, ad esempio quando A -> B e B -> A

Ho eseguito l'esempio precedente in un ciclo per un paio di minuti e i livelli di GC si muovevano molto ma la dimensione minima era ancora piccola.

+1

Che dire della perdita di memoria come indicato da AmitD? – Jim

+0

@Jim Buona domanda, ho aggiunto una risposta. –

+0

Peter, la perdita può verificarsi su ThreadLocals estesi poiché il thread sta per mantenere un riferimento. Pensa a decomprimere e dinamici classloader. – bestsss

3

set: imposta la copia del thread corrente di questa variabile locale del thread sul valore specificato.

Significato tutto ciò che era in quella posizione di memoria, verranno sovrascritti da quello che avete attraversato set

13

Perché ThreadLocal ha Map di currentThread e value, Ora, se non si rimuove il valore nel thread che stava usando quindi creerà una perdita di memoria.

È sempre necessario chiamare rimuovere perché ThreadLocal classe mette i valori dal Discussione Classe definito da ThreadLocal.Valori localValues; Ciò causerà anche il mantenimento del riferimento di Thread e oggetti associati.

Dal codice sorgente di ThreadLocal

il valore verrà impostato su null e la voce sottostante sarà ancora presente.

+0

Significa che senza 'remove' non sarà GCed? – Jim

+1

Non si tratta di valore, si tratta di 'Thread' che ha riferimento in' ThreadLocal' se non si chiama remove, non otterrà mai GCed. –

1

Se la variabile si sta cercando di remove sarà sempre set nelle prossime esecuzioni del filo, io non mi preoccuperei rimuoverlo. set sovrascriverà il suo valore.

Ma se si imposta tale variabile solo in alcune circense (ad esempio, quando si tratta solo un tipo specifico di richieste), rimuoverlo potrebbe essere conveniente in modo che non rimanga intorno quando, ad esempio, il thread viene rimesso in piscina.

1

Mi renderò semplice: Se estendi il ThreadLocal per qualsiasi motivo, utilizza remove(). Su vanilla ThreadLocale usare set(null). Fondamentalmente non usare ThreadLocal.remove() su un esteso ThreadLocal può portare a perdite di memoria (quelli ClassLoader più probabile)

Se avete bisogno di ulteriori dettagli perché, pubblicare un commento.

+0

Non capisco la tua differenziazione di 'set (null)' e 'remove'. Dovrei chiamare 'set (null)' prima di chiamare 'set'? Perché ciò causerebbe una perdita? – Jim

+0

@bestsss distinzione interessante. – irreputable

+0

@Jim, non rimuovere l'oggetto tramite 'set (null)' o 'remove()' e il thread continua ad essere la cosa che causa la perdita.Non è assolutamente necessario chiamare il set prima di impostare (xxx). – bestsss