ThreadLocal的目的就是为每一个使用ThreadLocal的线程都提供一个值,让该值和使用它的线程绑定,当然每一个线程都可以独立地改变它绑定的值。如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序.

关于的ThreadLocal更多内容,请参考《ThreadLocal》。
在阅读了ThreadLocal的源码后,我发现如果我们使用不恰当,可能造成内存泄露。经我测试,内存泄露的确存在。虽然该内存泄露,理论上上已经不算严重。
测试代码如下
ThreadLocalTest文件
package com.teleca.robin;
 
public class ThreadLocalTest {
 
public ThreadLocalTest()
{
 
}
ThreadLocal<Content> tl=new ThreadLocal<Content> ();
void start()
{
System.out.println("begin");
Content content=tl.get();
if(content==null)
{
content= new Content();
tl.set(content);
}
System.out.println("try to release content data");
//tl.set(null);//@1
//tl.remove();//@2
tl=null;//@3
content=null;//@4
System.out.println("request gc");
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end");
}
}
class Content
{
byte data[]=new byte[1024*1024*10];
protected void finalize()
{
System.out.println("I am released");
}
}
运行结果
begin
try to release content data
request gc
end
注意我们尝试在@3和@4处,释放对tl和content的引用,以便JAVA虚拟机回收content。但是测试结果表明还有对content的引用,以致它没有能被JAVA虚拟机回收。
我们必须把@1或@2处的代码打开,才能把让它让JAVA虚拟机回收content.推荐打开@2而不是@1

把@1或@2处的代码打开后的运行结果如下:

begin
try to release content data
request gc
I am released
end
另外注意,@3其实并不影响运行结果。
 
事实上每个Thread实例都有一个ThreadLocalMap成员变量,它以ThreadLocal对象为key,以ThreadLocal绑定的对象为Value。
.我们调用ThreadLocal的set()方法,只是把要绑定的对象存放在当前线程的ThreadLocalMap成员变量中,以便下次通过get()方法取得它。
ThreadLocalMap和普通map的最大区别就是它的Entry是针对ThreadLocal弱引用的,即当ThreadLocal没有其他引用为空时,JVM就可以GC回收ThreadLocal,从而得到一个null的key。
关于ThreadLocalMap的更多内容请参考《为ThreadLocal定制的ThreadLocalMap
 
ThreadlocalMap维护了ThreadLocal对象和其绑定对象之间的关系,这个ThreadLocalMap有threshold,当超过threshold时,
ThreadLocalMap会首先检查内部ThreadLocal引用(前文说过,ThreadLocal是弱引用可以释放)是否为null,如果存在null,那么把绑定对象的引用设置为null,以便释放ThreadLocal绑定的对象,这样就腾出了位置给新的ThreadLocal。如果不存在slate threadlocal,那么double threshold。
除此之外,还有两个机会释放掉已经废弃的ThreadLocal绑定的对象所占用的内存,
一、当hash算法得到的table index刚好是一个null 的key的threadlocal时,直接用新的ThreadLocal替换掉已经废弃的。
二、每次在ThreadLocalMap中存放ThreadLocal,hash算法没有命中既有Entry,需要新建一个Entry时,也调用cleanSomeSlots来遍历清理Entry数组中已经废弃的ThreadLocal绑定的对象的引用。
此外,当Thread本身销毁时,这个ThreadLocalMap也一定被销毁了(ThreadLocalMap是Thread对象的成员),
这样所有绑定到该线程的ThreadLocal的Object Value对象,如果在外部没被引用的话(通常是这样),也就没有任何引用继续保持,所以也就被销毁回收了。
 
从上可以看出Java已经充分考虑了时间和空间的权衡,但是因为置为null的ThreadLocal对应的Object Value在无外部引用时,任然无法及时回收。
ThreadLocalMap只有到达threshold时或添加entry时才做检查,不似gc是定时检查,
不过我们可以手工通过ThreadLocal的remove()方法或set(null)解除ThreadLocalMap对ThreadLocal绑定对象的引用,及时的清理废弃的threadlocal绑定对象的内存以。remove()往往还能做更多的清理工作,因此推荐使用它,而不使用set(null).
需要说明的是,只要不往不用的threadlocal中放入大量数据,问题不大,毕竟还有回收的机制。
 
被废弃了的ThreadLocal所绑定对象的引用,会在以下4情况被清理。
如果此时外部没有绑定对象的引用,则该绑定对象就能被回收了:
1 Thread结束时。
2 当Thread的ThreadLocalMap的threshold超过最大值时。
3 向Thread的ThreadLocalMap中存放一个ThreadLocal,hash算法没有命中既有Entry,而需要新建一个Entry时。
4 手工通过ThreadLocal的remove()方法或set(null)。
 
因此如果我们粗暴的把ThreadLocal设置null,而不调用remove()方法或set(null),那么就可能造成ThreadLocal绑定的对象长期也能被回收,因而产出内存泄露。
 
http://blog.csdn.net/hudashi/article/details/7076880
 
 

ThreadLocal的内存泄露(转)的更多相关文章

  1. ThreadLocal的内存泄露

    ThreadLocal的目的就是为每一个使用ThreadLocal的线程都提供一个值,让该值和使用它的线程绑定,当然每一个线程都可以独立地改变它绑定的值.如果需要隔离多个线程之间的共享冲突,可以使用T ...

  2. ThreadLocal源码解析,内存泄露以及传递性

    我想ThreadLocal这东西,大家或多或少都了解过一点,我在接触ThreadLocal的时候,觉得这东西很神奇,在网上看了很多博客,也看了一些书,总觉得有一个坎跨不过去,所以对ThreadLoca ...

  3. 面试:为了进阿里,死磕了ThreadLocal内存泄露原因

    前言 在分析ThreadLocal导致的内存泄露前,需要普及了解一下内存泄露.强引用与弱引用以及GC回收机制,这样才能更好的分析为什么ThreadLocal会导致内存泄露呢?更重要的是知道该如何避免这 ...

  4. ThreadLocal以及内存泄漏

    ThreadLocal是什么 ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度.但是如果滥用Thr ...

  5. 深入ThreadLocal之三(ThreadLocal可能引起的内存泄露)

    threadlocal里面使用了一个存在弱引用的map,当释放掉threadlocal的强引用以后,map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露. 最好 ...

  6. 【转载】Java中如何写一段内存泄露的程序 & ThreadLocal 介绍和使用

    可以参考这段文章: link A1:通过以下步骤可以很容易产生内存泄露(程序代码不能访问到某些对象,但是它们仍然保存在内存中): 上文中提到了使用ThreadLocal造成了内存泄露,但是写的不清不楚 ...

  7. ThreadLocal是否会引发内存泄露的分析(转)

    这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...

  8. ThreadLocal可能引起的内存泄露(转)

    threadlocal里面使用了一个存在弱引用的map,当释放掉threadlocal的强引用以后,map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露. 最好 ...

  9. ThreadLocal是否会导致内存泄露

    什么是内存泄露? 维基百科的定义:[内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存],我的理解就是程序失去了对某段内存的控制,那么这段内存就算是泄露了. ThreadLocal为什么会导致 ...

随机推荐

  1. Android 解决Gallery下ScrollView滑动事件冲突

    在Gallery下,里面内容过长超出屏幕,这时我们可以用ScrollView来滚动,但是这样做了以后,会发现一个问题,Gallery的滑动事件和ScrollView的滑动事件起冲突,这时我们可以自定义 ...

  2. hdu2089不要62(数位dp)

    #include <stdio.h> #include <string.h> ][]; ]; /* dp[i][0] 不含62,4 dp[i][1] 2开头 dp[i][2] ...

  3. 使用JustDecompile修改程序集

    原文:使用JustDecompile修改程序集        JustDecompile是Telerik公司推出一个免费的.net反编译工具,支持插件,与Visual Studio 2010,2012 ...

  4. 设计模式C++达到 3.抽象工厂

    简单工厂模式和工厂模式 要求 同类型的产品子类有共同的方法.这限制了产品子类的扩展.抽象工厂能client它提供了一个接口,它是client而不必指定产品的详细信息.创建多个产品系列产品对象.在归为一 ...

  5. “AIR SDK 0.0: AIR SDK location “...\devsdks\AIRSDK\Win” does not exist.”问题解决~

    原文同步至:http://www.waylau.com/air-sdk-0-0-air-sdk-location-does-not-exist-address/ 导入AS3项目时提示“AIR SDK ...

  6. Java EE (3) -- Java EE 6 Web Services Developer Certified Expert(1z0-897)

    Create an SOAP web service in a servlet container Create a RESTful web service in a servlet containe ...

  7. FPGA开机状态

    最近调试FPGA电路时发现一个问题,我从来没有注意过.我们都知道Xilinx的FPGA有三种功率M引脚,这是为了让我们配置三个引脚FPGA装载机模式,什么是主要的字符串.从字符串.并行等.,该手册有. ...

  8. win7,win8取得管理员权限 .reg文件

    Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\runas] @="获取管理员所有权" " ...

  9. svn创建并应用补丁

    有时,我们不能提交临时局部变化,而我们需要回滚到svn最新的版本号.然,这些变化,我们要保持.提交或发送给其他同事的未来review. 怎么做?非常easy,只需要两个步骤: (1)创建一个补丁文件并 ...

  10. WPF3D学习,立方体的绘制

    原文:WPF3D学习,立方体的绘制 以此为一个好的开始吧!一直都太懒,坚持写文章是个不错的开始!碰巧最近在研究WPF3D这块的知识,也为了练练自己的写作水平,整理这篇文章.新手上路,多多关照! 本文先 ...