当使用 ThreadLocal 时,每个线程都会有一个对应的 ThreadLocalMap,用来存储线程局部变量。如果线程不会被及时回收,而且每个线程都持有一个大的 ThreadLocalMap,就有可能导致内存溢出。

下面是一个可能导致内存溢出的例子:

public class ThreadLocalOOM {
    private static final int THREAD_NUM = 1000;
    private static final int LOOP_NUM = 100000;

    private static ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUM);

        for (int i = 0; i < THREAD_NUM; i++) {
            executorService.execute(() -> {
                threadLocal.set(new byte[1024 * 1024 * 5]);  // 5 MB
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                threadLocal.remove();
            });
        }
    }
}

上面的例子中,创建了 1000 个线程,每个线程都会在 ThreadLocal 中设置一个 5MB 大小的数组。然后线程会暂停 1 秒钟,最后再移除 ThreadLocal 中的值。由于每个线程都会持有一个 5MB 的数组,所以如果线程不会被及时回收,就会导致内存溢出。

为了避免这种情况,可以在使用 ThreadLocal 之后,手动调用 remove() 方法来清除线程局部变量。或者使用 InheritableThreadLocal,它会自动清除父线程中的线程局部变量。另外,合理控制线程池的大小也可以避免内存溢出问题。

Java ThreadLocal 内存溢出分析及解决方法

原文地址: https://www.cveoy.top/t/topic/o4Ge 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录