ThreadLocal内存泄漏示例

ThreadLocal内存泄漏是老生常谈的问题了,原理就不多说了,这里只简单回顾下

Thread类有个属性threadLocals,其实就是个map。

这个map的结构如下,key是ThreadLocal对象,是一个弱引用,value是调用threadLocal.set时设置的值。

下面我们通过示例来看看,ThreadLocal是如何造成内存泄漏的。

示例

示例代码如下:

java 复制代码
package com.example.commondemo;

import java.util.Scanner;

public class TestThreadLocal {

    public static void main(String[] args) throws Exception {
        Thread t = new Thread(() -> {
            setThreadLocal();
            while (true) {

            }
        });
        t.start();

        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        // 屏幕输入gc后,执行一次gc操作
        if (str.equals("gc")) {
            System.gc();
        }
    }

    private static void setThreadLocal() {
        // 这里用MyThreadLocal和MyThreadLocalObj,而不是ThreadLocal,没什么特别含义
        // 只是为了方便我们一会查看内存对象时方便查找
        MyThreadLocal threadLocal = new MyThreadLocal();
        threadLocal.set(new MyThreadLocalObj());
        threadLocal = new MyThreadLocal();
        threadLocal.set(new MyThreadLocalObj());
    }

}

public class MyThreadLocalObj {

}

// 这里用MyThreadLocal,而不是ThreadLocal,没什么特别含义
// 只是为了方便我们一会查看内存对象时方便查找
public class MyThreadLocal extends ThreadLocal<MyThreadLocalObj> {

}

代码很简单,我们在一个线程中new了两个MyThreadLocal,并在每个threadLocal中设置了一个MyThreadLocalObj对象。

我们期望的结果是什么呢?

  1. 当我们在屏幕输入gc之前(调用System.gc()之前),如果还没有进行过垃圾收集,我们dump出内存,应该能够看到内存中有MyThreadLocal两个对象

  2. 当我们输入gc后(调用System.gc()后),再次dump出内存,由于两个MyThreadLocal对象是弱引用,且我们代码中没有其他地方引用,两个MyThreadLocal对象应该会被回收。

另外说明一下,为了尽量减少干扰,我后面都会用命令行操作,每个执行的命令我会贴出来。

编译我们上面的代码,然后执行

java -cp . com.example.commondemo.TestThreadLocal

程序会一直运行,由于我们无法控制jvm的gc,所以在dump内存前,我们先看下是否执行过gc了,如果已经执行过至少一次gc,就看不到我们预期的结果了。

可以看到我们的程序还没有gc过,然后我们用jmap命令把内存dump出来

然后我们在程序运行界面输入gc,此时jvm会进行gc。

我们再次查看gc情况,可以看到jvm进行了一次YGC和FGC

再次dump内存

我们用visualvm打开"gc前.bin"和"gc后.bin"两个文件,可以很清楚看到,MyThreadLocal在gc后被回收了,但是我们在threadLocal中设置的两个对象MyThreadLocalObj并没有被回收,由于我们程序没有任何其他地方引用这两个MyThreadLocalObj对象,所以这两个对象已经泄漏了。

相关推荐
Hrain-AI3 分钟前
2026 企业 AI 编程智能体实战:Codex 与 Claude Code
开发语言·人工智能·kotlin
码上上班15 分钟前
docker课程
java·docker·容器
腻害兔19 分钟前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
wdfk_prog29 分钟前
嵌入式面试真题第 13 题:单硬件 Timer 下的高精度多路软件定时器架构设计
c语言·开发语言·面试·职场和发展·嵌入式
oort12341 分钟前
吃上了自家的细糠,还挺丝滑,用起来手感还行,OortCloud发布新版AI编程平台,下载 OortCodex,Token多,免费薅
大数据·开发语言·人工智能·ai编程
达子6661 小时前
第9章_HarmonyOs图解 用Java开发UI
java·ui·harmonyos
slandarer1 小时前
MATLAB | 泰勒图绘制,支持各种角度范围
开发语言·数学建模·matlab·nature·顶刊·泰勒图
mct1231 小时前
c++ iconv 字符utf-8转换gb2312失败
开发语言·c++
龙虾PRO3 小时前
能源与股票量化核心差异,AI全链路落地实操手册
java·面试·职场和发展
Marst Code3 小时前
Python 3.9 已停止维护!从 3.9 到 3.14 全版本深度对比,生产环境该选哪个?
开发语言·python