使用ThreadLocal引起的内存泄漏问题

用例:

先给大家看一段代码测试下:我们先设置了JVM堆内存的大小为30M。

new Thread(() -> {
	System.out.println("1==" + Runtime.getRuntime().freeMemory());
	threadLocal.set(new byte[1024 * 1024 * 10]);
	System.out.println("2==" + Runtime.getRuntime().freeMemory());
//            threadLocal.remove();
	try {
		Thread.sleep(5000);
		System.out.println("3==" + Runtime.getRuntime().freeMemory());
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}).start();

new Thread(() -> {
	try {
		Thread.sleep(2000);
		System.gc();
		System.out.println("3==" + Runtime.getRuntime().freeMemory());
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	System.out.println("1==" + Runtime.getRuntime().freeMemory());
	threadLocal.set(new byte[1024 * 1024 * 10]);
	System.out.println("2==" + Runtime.getRuntime().freeMemory());
//            threadLocal.remove();
	try {
		Thread.sleep(5000);
		System.out.println("3==" + Runtime.getRuntime().freeMemory());
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}).start();
1==23912512
2==13258592
3==17776072
1==17776072
Exception in thread "Thread-1" java.lang.OutOfMemoryError: Java heap space
	at com.thread.demo.Demo.lambda$main$1(Demo.java:68)
	at com.thread.demo.Demo$$Lambda$2/114935352.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
3==17734224

上面这段代码在使用ThreadLocal后没有及时调用threadLocal.remove()的结果,程序出现内存溢出错误。

当我们及时调用threadLocal.remove()后程序就是正常的了。

导出出现内存泄漏的原因:

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

我们都知道Thread类中有一个变量为 ThreadLocal.ThreadLocalMap threadLocals = null;

当我们在调用set方法时会先获取到当前线程,然后对当前线程的ThreadLocalMap对象进行set key value键值对。

如果当前线程一直存活,会导致对应的value一直存在,造成内存泄漏。

并且由于key是弱引用是会被垃圾回收器所回收的,这时候ThreadLocalMap中就会存在一个key为null value不为null的键值对。

如果执行了threadLocal.remove()方法后。

对应的value的引起就会被去掉,就是将null赋值给对应的这个变量。

这时候垃圾回收器就会回收掉这个value了。

注意事项:

特别是我们在使用线程池的时候,线程池中配置的核心线程是永远存在的,这时候一定要注意规范的调用threadLocal.remove()方法。

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值