ThreadLocal 内存泄漏原因和解决方法
一、ThreadLocal 内存泄漏的原因
ThreadLocal 的内存泄漏问题主要与其底层实现 ThreadLocalMap 的结构和垃圾回收机制有关。以下是核心原因:
1、ThreadLocalMap 的 Entry 设计
键(Key)是弱引用:ThreadLocalMap 中的键(Key)是 ThreadLocal 对象的弱引用(WeakReference<ThreadLocal<?>>)
值(Value)是强引用:Entry 中的值(Value)是强引用
2、弱引用的特性
当 ThreadLocal 对象,没有其他强引用指向它时(例如开发者将其置为 null),垃圾回收器(GC)会回收这个 ThreadLocal 对象
此时,ThreadLocalMap 中对应的 Entry 的 Key 会变为 null,但 Value 仍然是强引用,无法被 GC 回收
3、线程生命周期问题
如果线程是长时间运行的(例如线程池中的线程),并且 ThreadLocal 的 Value 未被清理:
Key 被回收后,Entry 的 Value 会一直存在,导致内存泄漏。
最终,ThreadLocalMap 中会积累大量 Key 为 null 的 Entry,占用内存
二、内存泄漏的示例场景
public class LeakExample {
private static ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
// 线程池中的线程会复用
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(() -> {
threadLocal.set(new byte[10 * 1024 * 1024]); // 设置大对象
// 没有调用 threadLocal.remove()
});
}
}
线程执行完毕后,ThreadLocal 的 Value(byte[10MB])会一直存在于 ThreadLocalMap 中,无法被回收
三、解决内存泄漏的方法
1、显式调用 remove()
关键操作:在使用完 ThreadLocal 后,调用 remove() 方法清理当前线程的 Entry。
最佳实践:使用 try-finally 确保清理:

2、将 ThreadLocal 声明为 static final
原因:如果 ThreadLocal 实例是非静态的,每次创建外部类实例时都会生成新的 ThreadLocal 对象,导致 ThreadLocalMap 中积累大量无用的 Entry
正确做法:

3、避免线程池中的线程长期持有 Value
线程池场景:线程会被复用,如果未清理 ThreadLocal,旧 Value 会一直存在。
解决方案:在任务执行前后调用 remove()。
四、JDK 对内存泄漏的优化
expungeStaleEntry() 方法:
在 ThreadLocalMap 的 get()/set()/remove() 方法中,JDK 会尝试清理 Key 为 null 的 Entry。
局限性:如果长时间不调用这些方法,泄漏仍会发生。
五、总结:如何避免内存泄漏
1、及时清理:在代码逻辑结束时调用 threadLocal.remove()。
2、使用 static final:减少不必要的 ThreadLocal 实例。
3、避免长生命周期线程:在池化线程场景中,显式清理 ThreadLocal。
4、工具检测:使用内存分析工具(如 MAT)检查 ThreadLocalMap 中的残留 Value。
六、关键理解
弱引用不是万能的:ThreadLocal 的弱引用仅解决了 Key 的内存泄漏,但 Value 仍需手动清理。
开发者责任:内存泄漏的根源是未正确管理 ThreadLocal 的生命周期,而非 JDK 设计缺陷。
ThreadLocal 内存泄漏原因和解决方法的更多相关文章
- 上Mysql com.mysql.jdbc.StatementImpl$CancelTask内存泄漏问题和解决方法
近来在负责公司短信网关的维护及建设,随着公司业务发展对短信依赖越来越严重了,短信每天发送量也比曾经每天40多w发送量暴增到每天达到200w发送量.由于是採用Java做发送底层,压力递增情况下不可避免的 ...
- Android 内存泄漏分析与解决方法
在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...
- c++内存泄漏原因及解决办法(智能指针)
内存泄漏 由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费. 内存泄露的 ...
- 使用HandyJSON导致的内存泄漏问题相关解决方法
在移动开发中,与服务器打交道是不可避免的,从服务器拿到的接口数据最终都会被我们解析成模型,现在比较常见的数据传输格式是json格式,对json格式的解析可以使用原生的解析方式,也可以使用第三方的,我们 ...
- MFC多线程内存泄漏问题&解决方法
在用visual studio进行界面编程时(如MFC),前台UI我们能够通过MFC的消息循环机制实现.而对于后台的数据处理.我们可能会用到多线程来处理. 那么对于大多数人(尤其是我这样的菜鸟),一个 ...
- jmeter(二十二)内存溢出原因及解决方法
jmeter是一个java开发的开源性能测试工具,在性能测试中可支持模拟并发压测,但有时候当模拟并发请求较大或者脚本运行时间较长时,压力机会出现卡顿甚至报异常————内存溢出, 这里就介绍下如何解决内 ...
- <转>jmeter(二十二)内存溢出原因及解决方法
本博客转载自:http://www.cnblogs.com/imyalost/category/846346.html 个人感觉不错,对jmeter讲解非常详细,担心以后找不到了,所以转发出来,留着慢 ...
- android 常见内存泄漏原因及解决办法
android常见内存泄漏主要有以下几类: 一.Handler 引起的内存泄漏. 在Android开发中,我们经常会使用Handler来控制主线程UI程序的界面变化,使用非常简单方便,但是稍不注意,很 ...
- jmeter 内存溢出原因及解决方法
jmeter是一个java开发的开源性能测试工具,在性能测试中可支持模拟并发压测,但有时候当模拟并发请求较大或者脚本运行时间较长时,压力机会出现卡顿甚至报异常————内存溢出, 这里就介绍下如何解决内 ...
- Windows 系统提示“内存不足”的原因及解决方法
Windows 系统提示“内存不足”的原因及解决方法 windows XP vista 及windows 7系统的电脑有时候会出现系统提示“内存不足”,这是由多方面原因造成的.本文具体分析下 ...
随机推荐
- Redisson实现分布式锁---原理
Redisson实现分布式锁(1)---原理 有关Redisson作为实现分布式锁,总的分3大模块来讲. 1.Redisson实现分布式锁原理 2.Redisson实现分布式锁的源码解析 3.Redi ...
- react 趟坑
最近一直在做react项目,发现一个bug,困扰了我两天. Can't perform a React state update on an unmounted component. This is ...
- Oracle生成awr报告操作步骤
1.cmd命令窗口 以sysdba身份登录Oracle 2.执行@?/rdbms/admin/awrrpt命令,并选择报告类型为HTML.输入天数以选择生成报告的时间段,一般默认为最近7天.输入报告开 ...
- .net 通过 HttpClient 下载文件同时报告进度的方法
通过 HttpClient 的 ContentLength 很多时候都可以拿到下载的内容的长度,通过 ReadAsync 可以返回当前读到的长度,将读取到的长度加起来就是已经下载的长度 看起来很简单, ...
- Kali Linux 安装教程
Kali Linux 安装教程 下载镜像文件 Kali官网下载 访问Kali官网(https://www.kali.org/ ),根据下图所示进行下载 清华大学开源软件镜像站下载 访问清华大学开源软件 ...
- Zabbix Proxy安装及替换Zabbix阿里云源脚本
zabbix proxy安装步骤 说明: Zabbix Proxy使用的是独立的数据库实例,如果放在一起数据容易遭到破坏;Proxy仅仅是一个数据采集的作用,其他的依然是依靠Server端实现,这就会 ...
- CF1326G 题解
题意: 蛛网树是一颗平面树,满足点是该树的凸包的顶点上等价于其是叶子. 给定一个平面树,求有多少种对点集的划分,使得每个划分出来的集合都是蛛网树. Solution 考虑树形 dp.设 \(f_u\) ...
- P3092 [USACO13NOV] No Change G 题解
传送门 题解 思路 看到 \(1\le k\le16\),我们想到状压DP. 以每枚硬币是否被使用为状态,对其进行枚举. 令 \(dp_i\) 表示状态 \(i\) 下最多能支付到第 \(dp_i\) ...
- 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-14- iframe操作-下篇(详细教程)
1.简介 通过前边两篇的学习,想必大家已经对iframe有了一定的认识和了解,是不是感觉和Python语言中的差不了多少,大同小异,最多就是不同开发语言的一些语法差异.今天这一篇主要是对iframe做 ...
- MAC消息认证码介绍
此MAC是密码学概念,与计算机网络不同 为什么有了摘要算法还要有MAC 摘要算法保障的是消息的完整性 归根到底就是由H(x)来保证x的完整 那么问题来了,如果我知道你所使用的摘要算法(例如中间人攻击) ...