1. ThreadLocal为什么会内存泄漏?
回答要点:
- ThreadLocalMap的Entry中key是弱引用,value是强引用
- 当ThreadLocal对象被回收后,key变为null,但value仍然存在
- 如果线程长期存活(如线程池),这些无效Entry会累积
- 导致对应的value对象无法被回收
2. 如何避免ThreadLocal内存泄漏?
回答要点:
- 基础方法:
- 使用后立即调用remove()
- 使用static final修饰ThreadLocal
- 高级方法:
- 封装工具类统一管理
- 结合AOP/拦截器自动清理
- 使用增强型ThreadLocal实现
- 特别情况:
- 线程池任务需要额外处理
- 避免存储大对象
3. ThreadLocal的key为什么设计为弱引用?
回答要点:
- 防止ThreadLocal对象无法被回收
- 如果使用强引用,即使ThreadLocal对象不再使用,由于ThreadLocalMap的引用,也无法被GC
- 弱引用是折中方案,虽然可能导致value泄漏,但相比key无法回收更可控
- 配合remove()使用可以完全避免问题
4. 线程池环境下如何正确使用ThreadLocal?
回答要点:
- 必须确保每次任务执行后清理:
- 在finally块中调用remove()
- 使用任务包装器确保清理
- 考虑使用增强实现:
- InheritableThreadLocal(有限场景)
- TransmittableThreadLocal(推荐)
- 监控手段:
- 定期检查线程的ThreadLocalMap
- 使用内存分析工具检测泄漏
5. 如何检测应用中是否存在ThreadLocal泄漏?
回答要点:
- 监控手段:
- 内存分析工具查看Thread对象
- 检查ThreadLocalMap中key为null的Entry
- 代码检查:
- 确认所有ThreadLocal都有对应的remove()
- 特别检查异常处理路径
- 测试方法:
- 强制GC后检查对象是否被回收
- 长时间压力测试观察内存增长