java 线程本地删除?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12424838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Threadlocal remove?
提问by Jim
When using a ThreadLocal
should I always call remove()
when I am done or when I do set
the old value is replaced anyway so remove
is redundant?
使用 a时,我ThreadLocal
应该总是remove()
在完成时调用还是在执行时调用set
旧值,无论如何都会替换旧值,所以remove
是多余的吗?
回答by Amit Deshpande
Because ThreadLocal
has Map
of currentThread
and value
, Now if you don't remove the value in the thread which was using it then it will create a memory leak.
由于ThreadLocal
拥有Map
的currentThread
和value
,现在,如果你不删除其使用它,然后它会创建一个内存泄漏线程的值。
You should always call removebecause ThreadLocalclass puts values from the ThreadClass defined by ThreadLocal.Values localValues;This will also cause to hold reference of Thread and associated objects.
您应该始终调用remove,因为ThreadLocal类从ThreadLocal.Values localValues定义 的Thread类中放置值;这也将导致持有 Thread 和相关对象的引用。
From the source code of ThreadLocal
从源代码 ThreadLocal
the value will be set to null and the underlying entry will still be present.
该值将设置为 null 并且底层条目仍将存在。
回答by Peter Lawrey
set
always replaces the old value.
set
总是替换旧值。
This is true for
这是真的
- Calendar.set() and Date.set()
- BitSet.set()
- List.set()
- setters
- Calendar.set() 和 Date.set()
- BitSet.set()
- 列表.set()
- 二传手
You mean without remove it will not be GCed?
你的意思是不删除它就不会被GCed?
It will not be removed until the thread dies. It won't disappear on you without you calling remove()
直到线死了,它才会被移除。不调用 remove() 它不会消失在你身上
Whether this is a memory leak or not depends on your program. You would have to create lots of threads with large thread local objects which you didn't need for some reason for it to matter. e.g. 1000 threads with a 1 KB object could waste up to 1 MB, but this suggest a design issue if you are doing this sort of thing.
这是否是内存泄漏取决于您的程序。您将不得不创建大量具有大型线程本地对象的线程,出于某种原因,您不需要这些对象。例如,具有 1 KB 对象的 1000 个线程可能会浪费多达 1 MB,但是如果您正在执行此类操作,这表明存在设计问题。
The only place you might get a memory leak is.
唯一可能发生内存泄漏的地方是。
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);
}
}
with -verbosegc
prints.
与-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
Note: the size after a full GC is the same 49484K
注意:full GC 后的大小是一样的 49484K
In the above case you will have a ThreadLocal which refers to the Thread which refers to the ThreadLocal. However, as the Thread is dead it doesn't cause a memory leak becasue it becomes a regard object i.e. when A -> B and B -> A
在上述情况下,您将有一个 ThreadLocal,它指的是 Thread,它指的是 ThreadLocal。然而,由于线程已死,它不会导致内存泄漏,因为它成为关注对象,即当 A -> B 和 B -> A
I ran the above example in a loop for a couple of minutes and the GC levels moved around alot but the minimum size was still small.
我在循环中运行了上面的示例几分钟,GC 级别移动了很多,但最小尺寸仍然很小。
回答by Tony The Lion
set
: Sets the current thread's copy of this thread-local variable to the specified value.
set
: 将此线程局部变量的当前线程副本设置为指定值。
Meaning whatever was in that memory location, will now be overwritten by what you passed through set
意味着该内存位置中的任何内容现在都将被您通过的内容覆盖 set
回答by Xavi López
If the variable you're trying to remove
will be always set
in next executions of the thread, I wouldn't worry about removing it. set
will overwrite its value.
如果您尝试使用的变量remove
将始终set
在线程的下一次执行中,我不会担心删除它。set
将覆盖其值。
But if you're setting that variable only in some circusmtances (for instance, when treating only a specific kind of requests), removing it might be convenient so that it doesn't stay around when, for instance, the thread is put back into the pool.
但是,如果您仅在某些情况下设置该变量(例如,仅在处理特定类型的请求时),则删除它可能会很方便,以便它不会停留在例如线程被放回游泳池。
回答by Rémi Bantos
Noyou do not have to "always call remove()" instead of set()
不,您不必“始终调用remove()”而不是set()
If you fear memory leaks doing so, here is what the javadocsays
如果你担心内存泄漏这样做,这是javadoc所说的
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
只要线程处于活动状态并且可以访问 ThreadLocal 实例,每个线程都持有对其线程局部变量副本的隐式引用;线程消失后,它的所有线程本地实例副本都将进行垃圾回收(除非存在对这些副本的其他引用)。
Thus not calling remove()will not prevent a thread-local instance to be properly garbage collected, and will not cause memory leaks by nature.
因此,不调用remove()不会阻止线程本地实例被正确地垃圾回收,并且本质上不会导致内存泄漏。
You can also take a look to ThreadLocal implementation, which use WeakReferencesfor this "implicit reference" mechanism
您还可以查看 ThreadLocal 实现,它使用WeakReferences来实现这种“隐式引用”机制
Butbeware of consistency with thread pools
但要注意与线程池的一致性
Using set()method only with a thread pool, you might prefer to remove()a ThreadLocal instance, instead of overriding it in another "work unit" using the same thread. Because you might want to avoid the situation where, for some reason, the set method is not invoked, and your ThreadLocal remain attached to a context/treatment it does not belong.
仅在线程池中使用set()方法,您可能更喜欢remove()一个 ThreadLocal 实例,而不是在另一个使用同一线程的“工作单元”中覆盖它。因为您可能希望避免由于某种原因未调用 set 方法,并且您的 ThreadLocal 仍然附加到它不属于的上下文/处理的情况。
回答by bestsss
I will make it simple:
If you extend the ThreadLocal for any reason use remove()
. On vanilla ThreadLocal use set(null)
.
Basically not using ThreadLocal.remove()
on an extendedThreadLocal can lead to memory leaks (ClassLoader ones most likely)
我会让事情变得简单:如果您出于任何原因扩展 ThreadLocal,请使用remove()
. 在 vanilla ThreadLocal 上使用set(null)
. 基本上没有使用ThreadLocal.remove()
上的扩展的ThreadLocal可以导致内存泄漏(类加载器最可能)
If you need more details why, post a comment.
如果您需要更多详细信息,请发表评论。
回答by lupeng ge
If the thread is done the threadLocalMap
will be done with the thread. You do not need to remove it. But if the thread is used recycling you need to remove the value of threadLocalMap
.
如果线程threadLocalMap
完成,则线程将完成。您不需要删除它。但是如果线程用于回收,则需要删除threadLocalMap
.