锁定老帖子 主题:关于ThreadLocal的内存泄露
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-07-02
最后修改:2010-07-09
事实上每个Thread实例都具备一个ThreadLocal的map,以ThreadLocal Instance为key,以绑定的Object为Value。而这个map不是普通的map,它是在ThreadLocal中定义的,它和普通map的最大区别就是它的Entry是针对ThreadLocal弱引用的,即当外部ThreadLocal引用为空时,map就可以把ThreadLocal交给GC回收,从而得到一个null的key。 这个threadlocal内部的map在Thread实例内部维护了ThreadLocal Instance和bind value之间的关系,这个map有threshold,当超过threshold时,map会首先检查内部的ThreadLocal(前文说过,map是弱引用可以释放)是否为null,如果存在null,那么释放引用给gc,这样保留了位置给新的线程。如果不存在slate threadlocal,那么double threshold。除此之外,还有两个机会释放掉已经废弃的threadlocal占用的内存,一是当hash算法得到的table index刚好是一个null key的threadlocal时,直接用新的threadlocal替换掉已经废弃的。另外每次在map中新建一个entry时(即没有和用过的或未清理的entry命中时),会调用cleanSomeSlots来遍历清理空间。此外,当Thread本身销毁时,这个map也一定被销毁了(map在Thread之内),这样内部所有绑定到该线程的ThreadLocal的Object Value因为没有引用继续保持,所以被销毁。 从上可以看出Java已经充分考虑了时间和空间的权衡,但是因为置为null的threadlocal对应的Object Value无法及时回收。map只有到达threshold时或添加entry时才做检查,不似gc是定时检查,不过我们可以手工轮询检查,显式调用map的remove方法,及时的清理废弃的threadlocal内存。需要说明的是,只要不往不用的threadlocal中放入大量数据,问题不大,毕竟还有回收的机制。 综上,废弃threadlocal占用的内存会在3中情况下清理: 1 thread结束,那么与之相关的threadlocal value会被清理 2 GC后,thread.threadlocals(map) threshold超过最大值时,会清理 3 GC后,thread.threadlocals(map) 添加新的Entry时,hash算法没有命中既有Entry时,会清理 那么何时会“内存泄露”?当Thread长时间不结束,存在大量废弃的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一个废弃ThreadLocal在map中命中)时。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-07-02
本文基于对源代码的理解,如有错误请指正
|
|
返回顶楼 | |
发表时间:2010-07-03
没看过源代码,理论上是这样吧。
Thread有长时间不结束的情况吗?除非定时器,但是一个应用的定时器最多也是有限的几 个,如果一个应用有长时间不结束的Thread,就要检查代码写的是否有问题了。 另外,一个应用处理高并发的时候都会建立线程池,控制线程的最大值。 我觉得还是可以使用Threalocal来做应用开发的。 |
|
返回顶楼 | |
发表时间:2010-07-03
yumcn.com 写道 没看过源代码,理论上是这样吧。
Thread有长时间不结束的情况吗?除非定时器,但是一个应用的定时器最多也是有限的几 个,如果一个应用有长时间不结束的Thread,就要检查代码写的是否有问题了。 另外,一个应用处理高并发的时候都会建立线程池,控制线程的最大值。 我觉得还是可以使用Threalocal来做应用开发的。 恩,因为一直有人说ThreadLocal存在内存泄露问题,我才探究了一下,事实上问题不大。所谓内存泄露更多是出于一种性能的考量 |
|
返回顶楼 | |
发表时间:2010-07-04
为啥这么多人投隐藏,如果LZ那里说的不对可以指出,让大家学习下呀。我觉得至少LZ精神可嘉的。
|
|
返回顶楼 | |
发表时间:2010-07-04
赞楼主的精神先,但个人有个小建议, 在解释文字中,可以适量加一些代码,或者使文章更有可读性。
|
|
返回顶楼 | |
发表时间:2010-07-04
static ThreadLocal
|
|
返回顶楼 | |
发表时间:2010-07-04
最后修改:2010-07-04
- -! 你的意思是说:ThradLocal的内部类ThreadLocalMap这个map下的Entry在某些情况下存在内存泄漏吗?
但这个Entry是弱引用,应该是被GC启动时无条件回收吧?而弱引用并不被JVM"标记",每次GC都回收的呀,还是我理解有误? |
|
返回顶楼 | |
发表时间:2010-07-05
要善于和je的恶势力作斗争,精华了。
|
|
返回顶楼 | |
发表时间:2010-07-05
yumcn.com 写道 没看过源代码,理论上是这样吧。
Thread有长时间不结束的情况吗?除非定时器,但是一个应用的定时器最多也是有限的几 个,如果一个应用有长时间不结束的Thread,就要检查代码写的是否有问题了。 另外,一个应用处理高并发的时候都会建立线程池,控制线程的最大值。 我觉得还是可以使用Threalocal来做应用开发的。 用ThreadLocal来做开发当然没问题。说白了,SUN引入ThreadLocal无非就是在解决变量共享冲突问题上用空间来换时间,所以处理不好有泄漏应该算是合理的。 我在前一阵刚读过ThreadLocal的源代码,对比LZ的分析很惭愧啊,看来应该多学习LZ的精神啊。 引用 那么何时会“内存泄露”?当Thread长时间不结束,存在大量废弃的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一个废弃ThreadLocal在map中命中)时。 如果当ThreadLocal遇到线程池,那么发生泄漏的几率会大一些呢? |
|
返回顶楼 | |