java threadlocal内存泄露
「Java ThreadLocal 内存泄露」指的是在使用 ThreadLocal 时,由于线程长期存活、引用未被清理,导致对象无法被垃圾回收的现象。它和线程池、Web 容器中的请求处理线程,以及 ThreadLocal 的存储结构密切相关。
基本含义与用途
ThreadLocal 为每个线程提供独立的变量副本,常用于保存用户会话、数据库连接、事务上下文等线程私有的数据。它的内部实现是每个线程持有一个 ThreadLocalMap,键是 ThreadLocal 对象本身,值是业务数据。这种设计让线程之间互不干扰,读取时也不需要加锁。
常见问题
内存泄露通常发生在使用线程池的场景。线程执行完任务后不会立刻销毁,而是被复用,ThreadLocalMap 中的 Entry 会一直持有 value 的强引用。如果 Entry 的 key(ThreadLocal 对象)被回收,key 变成 null,但 value 仍然被线程强引用,这块内存就无法释放。虽然 ThreadLocalMap 在扩容或清理时会尝试清除 key 为 null 的 Entry,但这并不及时,长期积累就可能造成泄露。另一个常见问题是忘记调用 remove,尤其是在请求结束或任务完成后没有手动清理。
怎么判断与怎么选
判断是否存在泄露,可以观察线程池长期运行后内存占用是否持续上升,或用内存分析工具查看 ThreadLocalMap 中是否有大量 key 为 null 的 Entry。使用建议是:尽量用 static final 修饰 ThreadLocal,避免频繁创建;在 finally 块中调用 remove,确保线程复用前清理数据;如果只是方法内临时使用,优先考虑把数据作为参数传递,而不是放进 ThreadLocal。理解它的生命周期,比单纯记住“记得 remove”更重要。