ThreadLocalMap-Entry的key是弱引用 value是强引用

ThreadLocal内存溢出问题

内存泄露的本质是Entry不能被回收,
避免内存泄露的方法:
(1)是否手动删除了Entry;使用完ThreadLocal,调用其remove方法删除对应的Entry,就能避免内存泄漏
(2)CurrentThread有没被关闭;由于ThreadLocalMap是Thread的一个属性,被当前线程所引用,所以ThreadLocalMap的生命周期跟Thread一样长。所以,在使用完ThreadLcoal后当前Thread也随之结束,ThreadLocalMap也就自然会被GC回收,避免了内存泄漏

Entry的key是弱引用 value是强引用

1.ThreadLocalMap中的Key为什么使用弱引用

key如果使用强引用 如果没有主动删除Entry 那么只有线程结束的时候ThreadLocal才会被回收
ThreadLocal内存溢出问题
在这里插入图片描述
但是有一种危险是,如果线程是线程池的,在线程执行完代码的时候并没有结束,只是归还给线程池,这个时候ThreadLocalMap和里面的元素是不会回收掉的。

在ThreadLocalMap中的set/getEntry中,会对Key = NULL(即ThreadLocal = NULL)的进行判定,如果为NULL,将会把value也置为NULL。
这就意味着:使用完Thread Local,CurrentThread仍然运行的情况下,就算忘记remove(),弱引用也会比强引用多一层保障。

2.Value为什么是强引用

这里假设value和threadlocal都是弱引用,假如threadlocal除了 被Entry这个弱引用所引用之外,还被强引用(使用threadLocal时threadLocal对象肯定是被强引用的,当不被使用时也就没被强引用这时候Gc可回收),但这时threadLocal.set(value),value的值没被其它对象引用,只是传递给thread,也就是value 这时只被Entry这个弱引用所引用,这时候发生gc,threadlocal不会被回收,value回被回收 ,导致通过threadlocal获得value值时获得为Null。

3.Value存在内存泄露

Value的惰性删除
在这里插入图片描述
我们知道expungeStaleEntry() 方法是帮助垃圾回收的,根据源码,我们可以发现 get 和set 方法都可能触发清理方法expungeStaleEntry(),所以正常情况下是不会有内存溢出的。
但是如果我们没有调用get和set的时候就会可能面临着内存溢出。
所以不再使用的时候调用remove(),加快垃圾回收,避免内存溢出。

4.ThreadLocal对象一直存在时一定要remove()

假设Controller 对应的serviceImpl 有一个ThreadLocal对象
ThreadLocal对象 spring生命周期 保证应用重启前他一直存在的
所以Entry的key不为空 Entry一直存在 get()/set()是不能清除value的 ,Value是强引用 所以有可能造成:
1)内存溢出
2)第二次调用同一个线程 会有数据污染
所以用完就删除

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值