ThreadLocal什么时候会出现OOM的情况?为什么?

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

在threadlocal的生命周期中,都存在这些引用. 看下图: 实线代表强引用,虚线代表弱引用.

在这里插入图片描述

每个thread中都存在一个map, map的类型是ThreadLocal.ThreadLocalMap。 Map中的key为一个Threadlocal实例. 这个Map的确使用了弱引用,不过弱引用只是针对key. 每个key都弱引用指向threadlocal. 当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收. 但是,我们的value却不能回收,因为存在一条从current thread连接过来的强引用. 只有当前thread结束以后, current thread就不会存在栈中,强引用断开, Current Thread, Map, value将全部被GC回收.
  threadlocal内存模型

所以得出一个结论就是只要这个线程对象被gc回收,就不会出现内存泄露,但在threadLocal设为null和线程结束这段时间不会被回收的,就发生了我们认为的内存泄露。其实这是一个对概念理解的不一致,也没什么好争论的。最要命的是线程对象不被回收的情况,这就发生了真正意义上的内存泄露。比如使用线程池的时候,线程结束是不会销毁的,会再次使用的。就可能出现内存泄露。

PS.Java为了最小化减少内存泄露的可能性和影响,在ThreadLocal的get,set的时候都会清除线程Map里所有key为null的value。所以最怕的情况就是,threadLocal对象设null了,开始发生“内存泄露”,然后使用线程池,这个线程结束,线程放回线程池中不销毁,这个线程一直不被使用,或者分配使用了又不再调用get,set方法,那么这个期间就会发生真正的内存泄露。

划重点-总结一下:

  1. ThreadLocal是什么?
    每个线程在对内存中开辟的一块工作内存,同时把线程的共享数据拷贝了一份放进去,相当于做的本地副本,不会像synchronized一样每次修改都要同步到主内存中
  2. ThreadLocal有什么用?
    • 工作线程的数据交互主要是本地数据和主内存数据的交互,当数据存储在本地内存中,可以大大提高读取效率,避免了线程阻塞造成的cpu的吞吐下降;
    • 在多线程中每个线程中都要维护sesion,可以提高对独有资源的工作效率;
  3. 发生内存泄露原因?
    • synchornized是保证了主内存数据的一致,是时间换空间:通过阻塞一个共享变量,共享一小块内存空间;
    • threadLocal是通过建立线程的副本数据,空间换时间
    • ThreadLocalMap的Key为弱引用,当threadlocal对象被回收(value在ThreadLocalMap调用get、set、remove的时候就会被清除),这时将key设置为null的entry。但是threadlocal一直不会被回收,导致内存的泄露
    1. 如何避免呢?
      其实在调用threalocalMap的get/set方法时,会对key=null的entry(threadlocal对象=null)进行回收,也可以在调用结束时调用remove方法进行释放。
转载地址:https://www.cnblogs.com/onlywujun/p/3524675.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值