Handler消息机制(3)----ThreadLocal的内存泄漏

内存泄漏是什么?

  • 内存泄露为程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光,内存泄漏的原因是类成员的生命周期大于类对象的生命周期,换句话说就是一个需要销毁的对象由于成员被外部引用而无法销毁。广义并通俗的说,就是:不再会被使用的对象或者变量占用的内存不能被回收,就是内存泄露。

为了搞清内存泄漏问题和垃圾回收问题,我们要搞清楚java的四种引用类型:

  • 强引用:我们常常new出来的对象就是强引用类型,只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足的时候

  • 软引用:使用SoftReference修饰的对象被称为软引用,软引用指向的对象在内存要溢出的时候被回收

  • 弱引用:使用WeakReference修饰的对象被称为弱引用,只要发生垃圾回收,若这个对象只被弱引用指向,那么就会被回收

  • 虚引用:虚引用是最弱的引用,在 Java 中使用 PhantomReference 进行定义。虚引用中唯一的作用就是用队列接收对象即将死亡的通知

ThreadLocal的内存泄漏分析

先上一部分代码:

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    ...
}

从上述代码中可以看出,每一个Thread维护一个ThreadLocalMap,里面的Key是弱引用ThreadLocal实例,value是线程变量的副本。这些对象的引用关系如下图:

在这里插入图片描述

图中强引用为实心箭头,弱引用为虚线箭头。

从上图可以看出,ThreadLocalMap使用ThreadLocal的弱引用作为key,如果这个ThreadLocal不存在外部强引用时,这个Key势必就会被GC回收,这样就会导致ThreadLocalMap的Key为null,但是value还存在着强引用,只用Thread线程退出之后,value的强引用链才会断,也就是说,如果当前线程迟迟不结束,这些Key为null的value就会一直存在强引用链,永远不会被回收掉,就造成了内存泄漏

那么问题来了,既然我们都知道让ThreadLocal作为一个弱引用会有这个弊端,那么为什么要让这个key使用这个弱引用呢?

  • 我们知道,及时key使用弱引用的ThreadLocal,会造成key为null的情况,但是我们上一篇文章中说了,在每次调用ThreadLocalMap.set()/get()方法时,都有很高的概率会顺便清理掉无效对象。弱引用也给我们了一个解决的方式,就是每次使用完ThreahLocal之后,显式调用其remove()方法,来清除key为null的value值。
  • 如果让key使用强引用,ThreadLocalMap就持有ThreadLocal的强引用。然而ThreadLocalMap与Thread的生命周期一样长,如果我们不手动删除的话,ThreadLocal就不会被回收,所以我们需要每次用完ThreadLocal之后手动remov()一下,这就不会造成内存泄露。

ThreadLocal的正确使用方式

  • 每次使用完ThreadLocal都调用它的remove()方法清除数据
  • 将ThreadLocal变量定义成private static,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉 。

总结

由于Thread中包含变量ThreadLocalMap,因此ThreadLocalMap与Thread的生命周期是一样长,如果都没有手动删除对应key,都会导致内存泄漏。使用弱引用可以多一层保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set(),get(),remove()的时候会被清除。因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值