ThreadLocal出现OOM的场景和原理分析

本文分析了ThreadLocal出现OOM的场景,通过设置线程池和JVM参数,发现单线程池执行到一定次数会报OOM错误。还探讨了ThreadLocal内存泄漏的原因,指出线程不结束会使部分数据无法回收。同时解释了ThreadLocalMap使用弱引用的好处,并建议使用完ThreadLocal调用remove方法避免内存泄漏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、OOM的场景

1、代码

一个线程数为500的线程池,所有线程共享一个ThreadLocal变量,每一个线程执行的时候插入一个大的List集合。
在这里插入图片描述

在这里插入图片描述

2、设置JVM参数设置最大内存为256M

在这里插入图片描述

3、输出结果

在这里插入图片描述
可以看出,单线程池执行到第212的时候,就报了错误,出现OOM内存溢出错误。

二、ThreadLocal为什么会内存泄漏

1、首先看下使用ThreadLocal是如何保存数据的

public class ThreadLocal<T> {
	...
    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);
    }
    ...
}

可以看到,数据实际是保存在Thread t对象的threadLocals属性上的,key为threadLocal,value为调用threadLocal.set()方法传进来的值。

2、ThreadLocal的原理图

在这里插入图片描述
实线代表强引用,虚线代表弱引用

3、泄漏的原因

ThreadLocal使用完成后,ThreadLocalRef变为了null,ThreadLocalMap指向ThreadLocal的引用是弱引用,垃圾回收器一旦发现ThreadLocal上只有弱引用(一定请注意只有弱引用,没强引用),不管当前内存空间是否足够,那么都会回收ThreadLocal。此时ThreadLocal对象是可以被回收的。

但是由于线程一直存在,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。
在这里插入图片描述
只有当前thread结束以后,current thread就不会存在栈中,强引用断开,Current Thread、Map value将全部被GC回收。最好的做法是将调用threadlocal的remove方法

三、为什么ThreadLocalMap指向ThreadLocal的引用是弱引用?

如果key 使用强引用,引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,会导致ThreadLocal不会被回收,导致Entry内存泄漏。

key 使用弱引用的好处是:引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。

四、怎么避免内存泄漏呢?

每次使用完ThreadLocal,都调用它的remove()方法,清除数据。

在使用线程池的情况下,没有及时清理ThreadLocal,不仅是内存泄漏的问题,更严重的是可能导致业务逻辑出现问题。所以,使用ThreadLocal就跟加锁完要解锁一样,用完就清理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值