文档章节

ThreadLocal真会内存泄露?

Ambitor
 Ambitor
发布于 2015/12/04 11:07
字数 1456
阅读 111
收藏 0

最近心血来潮花了一周多时间把周克明先生的《深入理解JAVA虚拟机》的书看完了,没想到自己竟然能这么快的看完,虽不说全部掌握,但绝大部分都已经理解,想想大半年前自己的状态,这半年进步神速,这应该得益于现在的心境,而现在我也会开始写博客,因为我觉得能够很好的把自己掌握的东西表达出来才是真的理解和掌握。

ThreadLocal的内存泄露

前提

在看完书后对JVM产生了浓重的兴趣,我也开始搜寻更多的question去试着解答,所以近期在oschina看到一篇关于“ThreadLocal内存泄露”的文章,于是开始研究ThreadLocal是否会导致内存泄露的问题, 文章的笔者分析的非常好,但是有一个最核心的问题没有注意到,导致得出的结果恰恰相反,并且其中有一段关键的话是让人听得有点含糊的,笔者在这里把实现原理记录下来,说的有出入的地方,也欢迎更多的朋友拍砖指正。

分析ThreadLocal

ThreadLocal内存泄露”文中有一段话:

“每个key都弱引用指向threadlocal. 像上面code中的例子,当把threadlocal实例tl置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收. 但是,我们的value却不能回收,因为存在一条从current thread连接过来的强引用”

上段话总结的比较精致,但问题真实如此吗?笔者分析源代码把自己的理解记录下来,也让后面的读者一起学习: 其实ThreadLocal作为key断掉强引用t1之后 value是会被GC的,其原因是因为ThreadLocalMap中的Entry 继承了 WeakReference(注意是继承,说明Entry本身就是一个弱引用),我们再来看看源码:

static class Entry extends WeakReference<ThreadLocal> {
        Object value;

        Entry(ThreadLocal var1, Object var2) {
            super(var1);
            this.value = var2;
        }
 }

再看下ThreadLocal实现原理图,虚线表示弱引用,实线表示强引用。

注意:文章中分析WeakReference的泛型是ThreadLocal对象,并没有包含Entry中的Object value, 且后续并没有再用到这个ThreadLocal,所以ThreadLocal=null后没有任何强引用所以会被GC掉,但正如笔者前面标出的细节,ThreadLocalMap里面的Entry实际上是继承了WeakReference的,所以Entry本身就是个弱引用对象,所以当Entry中的Key ThreadLocal=null被GC掉后,并且value除了身为WeakReference的Entry对象的引用外不存在其他强引用的情况下,整个Entry是可能会被GC掉的。也就不存在因为value而内存泄漏了。(另外如果不知道WeakReference的,可以去看下Java WeakReference的理解与使用这篇文章)

思考:这个完美的设计来自是为了保证什么,或者说为什么这样设计?(这里不再详细的介绍ThreadLocal的实现)

首先ThreadLocalMap是存在每个线程里面的私有变量(极可能分配在TLAB中),Map中的Entry的key为ThreadLocal对象,考虑两个问题:

1、用户不想用这个对象了,直接把ThreadLocal=null,则ThreadLocal被GC,那么线程中value怎么回收?也就是ThreadLocalMap的Entry中的key为空了,value怎么办?(上面提到过ThreadLocalMap为私有变量,访问不到)

答:所以设计者把整个Entry都是WeakReference对象。当ThreadLocal被回收,则Entry没有强引用就可以直接被GC,保证了不会因为value而导致内存泄漏。

2、因为WeakReference<ThreadLocal>,所以即便用户代码中不执行ThreadLocal=null,而是代码中很少几率会用到,或者申明后就没用到过,那么在内存吃紧的时候,JVM也可以直接把Entry回收,那如果后期又要用ThreadLocal了,而ThreadLocalMap没有怎么办呢?

答:这个问题其实很简单。这样设计好处是为了当内存吃紧而编译分析ThreadLocal暂时用不到之后,可以直接GC掉从而释放部分内存。那如果后面又需要的时候怎么办呢?还记得ThreadLocal的get方法怎么写的嘛?如果get不到 是不是要调用SetInitialValue()方法重新生成?此举也可以在内存吃紧的时候缓解一部分压力。

所以。。。。膜拜JDK大神的设计吧。。简直66666

另外总结下:WeakReference、SoftReference这些个非强引用的引用,通常可以用来做缓存的对象,一般情况下我们本地缓存随着引用越来越多,导致了缓存的生命周期与应用的生命周期相同,当然我们通常通过LRU、限制个数等各种算法来避免缓存膨胀,但其实更好的做法是,在内存吃紧的时候缓存是可以被GC的,也就是整个缓存的大小是弹性的,在内存吃紧的时候我可以全部走DB或其他,这样可以减缓线上因为内存问题OOM。

 

注:版权所有转载请注明出处http://my.oschina.net/u/926166/blog/539228

 

© 著作权归作者所有

Ambitor
粉丝 74
博文 33
码字总数 33366
作品 0
深圳
技术主管
私信 提问
加载中

评论(2)

Ambitor
Ambitor 博主

引用来自“小乞丐”的评论

《深入理解JAVA虚拟机》这本书怎么样? 我今天看了下、还是没买、我想买 深入java虚拟机、老外写的!可是各大网站找不到!!

这本书写的不错哦,适合JVM刚入门的?你说的那本我没看过 不好评价啊。哈哈
小乞丐
小乞丐
《深入理解JAVA虚拟机》这本书怎么样? 我今天看了下、还是没买、我想买 深入java虚拟机、老外写的!可是各大网站找不到!!
JVM总结-OutOfMemoryError异常

在JVM规范中,除了程序计数器,虚拟机内存的其他几个运行区域都有可能发生OutOfMemoryError异常。 Java堆溢出: Java堆是用来存储对象实例,只要不停地创建对象实例,并且让GC ROOTS到对象之...

放心去流浪
04/09
70
0
在 JNI 编程中避免内存泄漏

此文转自 IBM developerWorks JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口。JNI 使 Java 代码程序可以与 native code 交互——在 Java 程序中调用 native code;在...

IBMdW
2011/04/26
1K
1
out就可以理解为System类的静态成员变量引用了PrintStream类的对象

面试题是实验室师兄面试提供的。两道题 题1:Java中System.out.print()如何理解? 查阅API文档,我们可以知道:System是Java中的一个类,而out是System类的成员 。 out属于java.io.PrintStre...

变小火
2018/06/29
0
0
Java 200+ 面试题补充 ThreadLocal 模块

让我们每天都有进步,老王带你打造最全的 Java 面试清单,认真把一件事做到极致。 本文是前文《Java 最常见的 200+ 面试题》的第一个补充模块。 1.ThreadLocal 是什么? ThreadLocal 是一个本...

王磊的博客
03/08
814
0
多线程并发神器--ThreadLocal

什么是ThreadLocal 可以理解成线程本地变量,传统的线程对一个变量操作时操作的是同一个对象,也存在线程安全的问题。 ThreadLocal是一个变量的本地副本,线程对变量的操作不会影响其他线程。...

java技术栈
2017/08/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

006-Docker中导出单个或多个tar包

docker中导出单个镜像和多个镜像的tar包 docker save [images] > [name.tar] docker save [images] [images] > [name.tar]...

伟大源于勇敢的开始
今天
6
0
Kotlin基础语法学习

安装好安卓studio,以及插件支持Kotlin 就可以在创建项目的时候选择 Kotlin语言了。 https://www.jianshu.com/p/4ab13691d681 参考手册: https://www.runoob.com/kotlin/otlin-android-setu...

T型人才追梦者
今天
4
0
java实现简单计算器

1.概述 之前作者写过一篇文章,也是关于计算器的,用的是C++与Qt,链接在这里 这次用java的swing写的(这差距好像有点大,好吧是qt太强了). 先上图: 2.UI 总体布局使用流布局. (1)文本框 文本框就...

Blueeeeeee
今天
4
0
纯CSS实现DIV悬浮(固定位置)

纯CSS实现的DIV悬浮效果(固定位置),兼容常用的浏览器:IE8、360、FireFox、Chrome、Safari、Opera、傲游、搜狗、世界之窗等。效果如下: 实现代码: <!DOCTYPE html> <html> <head> <meta ...

独钓渔
今天
6
0
OSChina 周二乱弹 —— 给我来个女菩萨

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @这次装个文艺青年吧 :#今日歌曲推荐#分享XXXTENTACION/Travis Barker的单曲《Pain = BESTFRIEND》: 《Pain = BESTFRIEND》- XXXTENTACION/...

小小编辑
今天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部