ThreadLocal内存泄漏排查:一次血淋淋的教训

Alex Chen | 2026-08-27T07:12:00 | Java, Spring Boot

分享一次线上OOM排查经历,罪魁祸首竟然是ThreadLocal配合线程池使用导致的内存泄漏

# ThreadLocal内存泄漏排查:一次血淋淋的教训 上周三凌晨两点,被运维的电话吵醒——线上服务OOM了。 ## 问题现象 监控显示Old Gen一直在涨,Full GC也回收不了。dump下来一看,好家伙,一堆`ThreadLocalMap$Entry`。 ## 排查过程 我们项目里有个`UserContext`,用ThreadLocal存当前用户信息: ```java // 看起来很正常对吧?但配合线程池就是个定时炸弹 public class UserContext { // ThreadLocal存储用户信息 private static final ThreadLocal holder = new ThreadLocal(); public static void set(UserInfo user) { holder.set(user); } public static UserInfo get() { return holder.get(); } } ``` 问题在于我们用了线程池,**线程不会销毁**,ThreadLocal的value就一直被强引用。虽然key是WeakReference,GC会回收key,但value还在! ## 解决方案 ```java // 方案一:用完必须remove try { UserContext.set(userInfo); // 业务逻辑 doSomething(); } finally { // 这一行千万不能忘! UserContext.remove(); } ``` 记住:**ThreadLocal + 线程池 = 内存泄漏**,用完一定要remove。这个坑希望大家别再踩了。

← Back to Blog