对 ThreadLocal 中内存泄露的理解

最近看多线程相关知识的时候了解到了 ThreadLocal 的内存泄漏问题,但一直不太清晰。今天又找了几个解析看了看,记录下我的理解。

对于每一个 Thread ,都有一个 ThreadLocalMap ,这个 ThreadLocalMap 的键值对是 <ThreadLocal,Object>。所以可以调用 ThreadLocal.set( Object ) ,实际上放进去的是 <this,Object>。可以看下 ThreadLocal 的代码:
 

   public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }


...

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

而这个 ThreadLocalMap 里面实现是这样的:

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;
            }
        }

        ......省略部分代码

        private Entry[] table;

        ......

        public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        }

        ......

        void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

        ......

        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }
        ......
}

可以看到 Entry 继承了 WeakReference<ThreadLocal<?>>,所以 Entry 创建的时候会用传进来的ThreadLocal 传给它的父类去初始化一个对象(类的对象构造规则是从父类执行到子类) WeakReference<ThreadLocal<?>> ,也就是创建了一个弱引用指向传进来的 ThreadLocal 。

当外部调用 ThreadLocal.set() 的强引用没了,这个弱引用就会在 GC 时被回收。此时 Entry 只剩下 Value 了。当 Thread 长期存活而 ThreadLocal 又不再使用,Entry 的 value 应当被回收,但是因为 Entry 被 ThreadLocalMap 强引用,而 ThreadLocalMap 被 Thread 强引用,所以无法回收这个 Entry ,也就是发生了内存泄露。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值