【面试造火箭3】ThreadLocal内存泄漏

这一天,程序员们终于想起「面试」支配的恐惧。

 

图片

 

以前一直知道ThreadLocal如果使用不当会导致内存泄漏,并且还认为是ThreadLocal中弱应用导致的(这是错误的❌)。今天仔细看了下源码和文档发现并不是那么回事~所以今天来分析一下ThreaadLocal的底层原理和内存泄漏吧~在讲之前先科普一下Java中的4种引用。

 

 

4种引用基础知识

 

1.强引用

新建一个对象就是一个强引用。只有当没有对象引用才会被回收。

 

2.软引用

softReference软引用,假如某个对象只有一个软引用关联,那么只有当JVM内存不足的时候才会被回收。

 

3.弱引用

weakReference弱引用,假如某个对象只有一个弱引用关联,GC回收时,遇见直接回收。

 

4.虚引用

虚引用一般开发不需要用到,GC回收时不会真正回收该对象,而是放进queue中检查,当真正没有引用时才回收。

 


 

 

 

ThreadLocal底层原理

这次的源码分析基于一个非常简单的多线程代码,这里主要实现了一个threadlocal和两个Thread,并且画出了线程与堆栈的内存关系。

 

图片

 

图片

 

值得注意到的是,这里面共有4个引用,我会顺着引用类型讲解,并引申出内存泄漏问题。请耐心阅读。

 

1.第一根引用是通过new ThreadLocal直接新建的,所以这里是强引用。

 

2.第二根引用也是强引用。

    a) 这里大家可能会有疑问,为什么这里又多出来了一个ThreadLocal?

        众所周知ThreadLocal是每个kv对,具有线程隔离性的数据管理工具。具体是怎么实现 的呢?原来每个线程都有一个属于自己的threadLocals对象,并且默认为空。每次set时都会把当前(main)的ThreadLocal对象作为key,ThreadLocal里的泛型对象object作为value。

    e.g. Thread中的ThreadLocal中key为tl.hash() / value 为 I am thread1 method。

 

3.第三根是kv对,强引用。

 

4.第4根是ThreadLocalMap特有的弱引用。

//每个线程都有自己的threadlocal对象

class Thread implements Runnable {

ThreadLocal.ThreadLocalMap threadLocals = null;

...

 

//这个方法是取自ThreadLocal的set方法,

private T setInitialValue() { 

   T value = initialValue(); 

   Thread t = Thread.currentThread(); 

   ThreadLocalMap map = getMap(t);  

   if (map != null)    

        map.set(this, value);   

   else    

        createMap(t, value);    return value;

}

 

 

 

 

面试考点1:为什么用这里用弱引用呢

如果用的是强引用,那么map中kv对无法正常释放会造成内存泄漏。

反之,如果是弱引用,1关联断开后,4由于是弱引用,并且没有其他地方使用,下次gc会自动清理

e.g.如上面的例子,1和4都强引用,无法正常释放。

 

面试考点2:ThreadLocal会造成内存泄漏请问是什么原因应该怎么避免

会有这么一个场景,tl不再需要了,被手动清空了。这个时候map中key变成空,map中的value无法访问。造成内存泄漏。

解决方法:每次tl使用完以后手动remove掉,或者thread正常关闭,内存就会释放。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值