0
点赞
收藏
分享

微信扫一扫

ThreadLocal 内存泄漏问题


本文说说ThreadLocal由于使用不当造成的内存泄漏问题

Thead和ThreadLocal的内存状况如下图,不了解的同学参考: ​​图解ThreadLocal核心原理​​

ThreadLocal 内存泄漏问题_ide


ThreadLocal 内存泄漏问题_内存溢出_02


如果线程太多,每个线程的value值都很大,是不是会造成内存溢出,写个程序模拟一下OOM的场景

1、程序模拟一下OOM

public class ThreadLocalTest {
public static void main(String[] args) throws InterruptedException {
testOOM();
}
private static void testOOM() throws InterruptedException {
int nThreads = 101;
ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < nThreads; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
threadLocal.set(new BigObject());
// 业务处理
}
});
}
Thread.sleep(10 * 1000);
}
static class BigObject {
byte[] _1M_bytes = new byte[1024 * 1024];
}
}
//

使用 ​​-Xms100m -Xmx100m​​ 参数运行程序

java.lang.OutOfMemoryError: Java heap space
at com.yh.stu.rocketmq.ThreadLocalTest$BigObject.<init>(ThreadLocalTest.java:67)
at com.yh.stu.rocketmq.ThreadLocalTest$1.run(ThreadLocalTest.java:28)

2、ThreadLocal OOM原因分析

为什么会OOM?因为线程池有101个线程,每一个线程都会有个Map,每个Map中存放了1M大小的对象,当循环执行到100左右的时候,堆内存就放满了,再向线程中放入Map时就OOM了

解决办法 :在​​// 业务处理​​​的后面加入​​threadLocal.remove()​​​,就不会OOM了,垃圾回收器会回收线程中的​​new BigObject()​​对象的空间

3、Thread中的 Map

从前文中我们感觉到,用户的数据是存在Thread的Map中的,ThreadLocal对象只是作为Map的key的方式存在着

ThreadLocal 内存泄漏问题_内存溢出_03

key是虚引用,内存不够垃圾回收时会回收,但value却不会, 看下图

ThreadLocal 内存泄漏问题_内存溢出_04

执行 ​​threadLocal.remove()​​​ 方法,将引用置为null,value对应的对象​​BigObject​​没有引用指向它,可以被回收

ThreadLocal 内存泄漏问题_内存溢出_05

附录-WeakReference使用

运行参数 ​​-Xms100m -Xmx100m​

public static void testWeakReference() throws InterruptedException {
while(true){
new Thread(){
@Override
public void run() {
WeakReference<BigObject> wref
= new WeakReference<>(new BigObject());
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();

Thread.sleep(100);
}
}

这个程序不会造成内存溢出,因为弱引用在内存不足时会被垃圾回收器回收


举报

相关推荐

0 条评论