java - ejemplo - threadlocal c#
Threadlocal eliminar? (7)
Debido a que ThreadLocal
tiene un Map
de currentThread
y value
, ahora, si no elimina el valor en el hilo que lo estaba usando, se creará una pérdida de memoria.
Siempre debe llamar a remove porque la clase ThreadLocal coloca valores de la clase Thread definida por ThreadLocal.Values ​​localValues; Esto también hará que se mantenga la referencia del subproceso y los objetos asociados.
Desde el código fuente de ThreadLocal
el valor se establecerá en nulo y la entrada subyacente seguirá presente.
Cuando ThreadLocal
un ThreadLocal
, siempre debo llamar remove()
cuando ThreadLocal
o cuando set
el valor anterior se reemplaza de todos modos, ¿entonces remove
es redundante?
Lo haré simple: si extiendes ThreadLocal por alguna razón, usa remove()
. En el set de uso ThreadLocal de vainilla set(null)
. Básicamente, no usar ThreadLocal.remove()
en un ThreadLocal extendido puede provocar pérdidas de memoria (las más probables de ClassLoader)
Si necesitas más detalles por qué, publica un comentario.
Si el hilo está terminado, el threadLocalMap
se hará con el hilo. No es necesario eliminarlo. Pero si el hilo se utiliza para reciclar, debe eliminar el valor de threadLocalMap
.
Si la variable que intenta remove
se set
siempre en las próximas ejecuciones del hilo, no me preocuparía eliminarla. set
sobrescribirá su valor.
Pero si está configurando esa variable solo en algunas circunstancias (por ejemplo, cuando se trata solo un tipo específico de solicitudes), eliminarla podría ser conveniente para que no se quede cuando, por ejemplo, el hilo se vuelve a colocar en la piscina.
set
: establece la copia del hilo actual de esta variable local del hilo al valor especificado.
Lo que significó que estaba en esa ubicación de memoria, ahora se sobrescribirá por lo que pasaste a través del set
set
siempre reemplaza el valor anterior.
Esto es cierto para
- Calendar.set () y Date.set ()
- BitSet.set ()
- List.set ()
- setters
¿Quieres decir que sin quitarlo no será GCed?
No se eliminará hasta que el hilo muera. No desaparecerá en ti sin que llames remove ()
Si esto es una pérdida de memoria o no depende de su programa. Tendría que crear muchos subprocesos con objetos locales de subprocesos grandes que no era necesario por alguna razón para que importen. Por ejemplo, 1000 hilos con un objeto de 1 KB podrían desperdiciar hasta 1 MB, pero esto sugiere un problema de diseño si está haciendo este tipo de cosas.
El único lugar donde puede obtener una pérdida de memoria es.
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 impresiones de -verbosegc
.
[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: el tamaño después de un GC completo es el mismo 49484K
En el caso anterior, tendrá un ThreadLocal que se refiere al Thread que se refiere al ThreadLocal. Sin embargo, como el hilo está muerto, no causa una pérdida de memoria porque se convierte en un objeto de consideración, es decir, cuando A -> B y B -> A
Ejecuté el ejemplo anterior en un bucle durante un par de minutos y los niveles de GC se movieron mucho, pero el tamaño mínimo todavía era pequeño.
No , no tiene que "llamar siempre a remove () " en lugar de a set ()
Si tienes miedo de las fugas de memoria, aquí está lo que dice el javadoc
Cada subproceso contiene una referencia implícita a su copia de una variable local de subproceso siempre que el subproceso esté vivo y la instancia de ThreadLocal esté accesible; una vez que el hilo desaparece, todas sus copias de las instancias locales del hilo están sujetas a la recolección de basura (a menos que existan otras referencias a estas copias).
Por lo tanto, no llamar a remove () no evitará que una instancia de subproceso local se recoja correctamente y no causará pérdidas de memoria por naturaleza.
También puede echar un vistazo a la implementación de ThreadLocal, que usa WeakReferences para este mecanismo de "referencia implícita"
Pero ten cuidado con la coherencia con los grupos de subprocesos
Usando el método set () solo con un grupo de subprocesos, es posible que prefiera eliminar () una instancia de ThreadLocal, en lugar de anularla en otra "unidad de trabajo" utilizando el mismo subproceso. Porque es posible que desee evitar la situación en la que, por algún motivo, no se invoca el método set y su ThreadLocal permanece vinculado a un contexto / tratamiento al que no pertenece.