ThreadLocal内存泄漏分析

ThreadLocal内存泄漏问题。

ThreadLocal线程局部变量,保证每个线程都有自己独立的副本,避免线程之间的变量共享。下面我们以Page对象为例,分析一下ThreadLocal内存的结构,以及可能发生的内存泄漏问题。
代码示例

public class RandomTest {
	public static void main(String[] args) {
		ThreadLocal<Page> pageLocal = new ThreadLocal<Page>();
		Page page = new Page();
		pageLocal.set(page);
	}
}
class Page{
	private int num;

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}
}

内存中的结构。

每一个Thread对象内部都有一个ThreadLocalMap对象,内部的key为ThreadLocal。为弱引用。也是容易引发内存泄漏的问题关键。Value为放入的对象,本章案例为Page对象。当ThreadLocalRef为空时。ThreadLocal对象就只包含弱引用。当发生GC时就会被回收掉。ThrealLocal在调用get和set方法时都会调用cleanSomeSlots方法将key为null的清除掉。或者可以将使用完的调用ThreadLocal.remove方法去除,避免内存泄漏。
源码查看:

private void set(ThreadLocal<?> key, Object value) {

// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.

Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);

for (Entry e = tab[i];
     e != null;
     e = tab[i = nextIndex(i, len)]) {
    ThreadLocal<?> k = e.get();

    if (k == key) {
        e.value = value;
        return;
    }

    if (k == null) {
        replaceStaleEntry(key, value, i);
        return;
    }
}

tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
    rehash();
}
private boolean cleanSomeSlots(int i, int n) {
    boolean removed = false;
    Entry[] tab = table;
    int len = tab.length;
    do {
        i = nextIndex(i, len);
        Entry e = tab[i];
        if (e != null && e.get() == null) {
            n = len;
            removed = true;
            i = expungeStaleEntry(i);
        }
    } while ( (n >>>= 1) != 0);
    return removed;
}

通过上面分析,内存泄漏的场景只有,当ThreadLocalRef为null,并且之后该线程放入线程池中,后面没有调用过get,set以及remove方法。那么ThreadLocalMap对象中的ThradLocal对象被回收,ThreadLocalMap的value--Page对象就存在堆内存中无法回收,造成内存泄漏。

转载于:https://my.oschina.net/hongliangsun/blog/1546438

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值