ThreadLocal内存泄露分析
来源:互联网 发布:新手音乐制作软件 编辑:程序博客网 时间:2024/06/16 11:27
1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收?
2. 弱引用什么情况下回收?
3. JAVA的ThreadLocal和在什么情况下会内存泄露?
带着这些疑问,自己模拟了一下ThreadLocal.ThreadLocalMap的结构,先展示下自己涉及的结构:
![](http://img.my.csdn.net/uploads/201303/10/1362880264_4089.png)
自己实现一个simple的ThreadLocalMap,里面用一个entry用来存放由自己模拟的ThreadLocal调用set方法set进去的值。
并且和JDK的ThreadLocalMap一样里面Entry对象的key用weakReference封装。
Main方法如下:
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0081/3945/5567355d-0753-3084-bee5-d5577f63dcba.png)
设置运行参数:
-verbose:gc
看输出结果:![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0081/3939/3b0e87f7-b47a-3b93-af78-682b0696a1f9.png)
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0081/3939/3b0e87f7-b47a-3b93-af78-682b0696a1f9.png)
这里我已经模拟出了内存泄露的问题,可以看到FULL GC以后,内存还是被占用,且仔细观察可以看到,这个map中的Key已经有为null了。换句话说你通过Key已经不能获取到value了,当然map.get(null)也是可以的,不过
JAVA里的ThreadLocal不会这么去做,因为Map中key==null的元素可能不唯一。
从我的Main方法中可以看到,我有th=null的操作,但是还是有内存泄露,原因稍后分析。但有一点可以确定:th=null在这里不能如我们想象的将ThreadLocal th 的引用释放掉后,里面的key,value对象也释放,可能会有疑问我这里持有了ThreadLocalMap的引用tm所以不会回收,但实际上,手动设置JAVA的ThreadLocal为null时,当前线程任然持有ThreadLocalMap的引用,所以不会回收我这里和JAVA是类似的。
回到刚开始提出的3个问题,一一解答:
1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收?
会被回收,如上图所示。key 已经有null的情况了。第一个Key不为null,原因在第二点。在经历过FULL GC后 所有的key都被回收了。
2. 弱引用什么情况下回收?
弱引用在GC(包括MinitorGC和Full GC)时,被扫描到就会被回收,但是有一个前提,该弱引用在外部没有被引用到(这个时候外部的引用等于强引用)。
换句话说,如果我main方法中持有一个key的引用,哪怕他put进Map后被设置为弱引用的,也不会被回收。见下图:
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0081/3935/dd854d12-b219-337a-83d6-c12d2f74435f.png)
GC 日志:
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0081/3937/69557c53-b437-3f24-b354-71a91cf9b0f8.png)
3. JAVA的ThreadLocal和在什么情况下会内存泄露?
答案是不会,原因如下图,在我们调用ThreadLocal.set()的时候,会做一个将Key== null 的元素清理掉的工作,具体做法是:
第一步:ThreadLocalMap 拿threadLocalHashCode与长度减一相与,求出哈希表的位置下图中的 i 。
第二步:编列Entry,如果找到key相等的,覆盖原值! 或者找到key==null的,将值set进去,并且将遍历时路过的key==null的元素和他的value都置为null,,释放内存。
第三步:最后一个if条件时,做rehash的动作,即:将Entry里的元素重新计算一下Hash值,放到合适的位置去,猜想是为了加快下次访问的速度。
![](http://dl.iteye.com/upload/attachment/0081/3931/d9871918-250c-3108-8eb4-cad5664ccd31.png)
总结:
从这里看出,JAVA的ThreadLocal对Key使用到了弱引用,但是为了保证不再内存泄露,在每次set.get的时候主动对key==null的entry做遍历回收。
虽然不会造成内存泄露,但是因为只有在每次set,get的时候才会对entry做key==null的判断,从而释放内存,所以可能使大对象在内存中存活很长一段时间,从而占用内存。
所以,我们在使用完ThreadLocal里的对象后最好能手动remove一下,或者至少调用下ThreadLocal.set(null)。
值得注意的是ThreadLocal中的key是当前当前ThreadLocal自己,就像上面模拟的外部持有强引用的情 况,ThreadLocal.ThreadLocalMap中的key==null情况很少出现,因为,大部分情况ThreadLocal是以单例模式一 直存在的。
http://liuinsect.iteye.com/blog/1827012
0 0
- ThreadLocal内存泄露分析
- ThreadLocal深入理解与内存泄露分析
- ThreadLocal 内存泄露的实例分析
- ThreadLocal的内存泄露
- ThreadLocal的内存泄露
- ThreadLocal内存泄露问题
- ThreadLocal内存泄露(上)
- ThreadLocal内存泄露(下)
- 反驳:Threadlocal存在内存泄露
- ThreadLocal可能引起的内存泄露
- ThreadLocal可能引起的内存泄露
- ThreadLocal可能引起的内存泄露
- ThreadLocal可能引起的内存泄露
- 【并发】ThreadLocal可能引起的内存泄露
- ThreadLocal可能引起的内存泄露
- 内存泄露问题分析
- 内存泄露问题分析
- Android内存泄露分析
- 练习一1012
- Java7 ForkJoin 源码分析
- SQLServer 根据执行计划创建索引
- 忘记svn密码怎么办
- 自定义 ForkJoinPool
- ThreadLocal内存泄露分析
- ThreadLocal的内存泄露
- 不同网段实现打印机共享
- java threadLocal 测试
- 可否强制修改常量的值?
- ElasticSearch:版本冲突处理(事务控制)
- Frament的基本概念和解析
- AndBug 安装
- elasticsearch权威指南 学习3