You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Heap dump内存泄漏排查求助:无明显可疑项,堆主要被byte[]等数组占用

ThreadLocal 中存在 Encoders/Decoders 的常见成因

大多数序列化、网络通信框架会将非线程安全的编解码器实例存入ThreadLocal实现线程级复用,避免每次请求重复创建对象的性能开销,常见的包括Netty的缓冲区编解码器、Jackson的JSON序列化器、Protobuf的编解码工具、OkHttp的响应解析器等。
如果服务使用的是核心线程不会销毁的常驻线程池,线程处理完任务后不会主动清理ThreadLocal中的内容,这些编解码器实例就会一直驻留在内存中,而绝大多数编解码器内部都会持有byte[]、char[]、int[]类型的缓冲数组,刚好匹配你堆内存中三类数组占比最高的观测结果。

大量处于等待状态的线程会放大泄漏问题:如果线程池核心线程数配置远高于实际业务需要的并发量,就会出现大量线程处理完任务后进入WAITING状态长期闲置,每个闲置线程都会携带一套完整的ThreadLocal编解码器实例,最终累积的内存占用会远超预期。


后续排查方向

  • 先确认编解码器的归属:在Yourkit中打开任意线程的threadLocals存储结构,查看Encoders、Decoders类的全限定名,确认属于第三方依赖还是自研组件。
  • 校验编解码组件的使用逻辑:如果是第三方组件,查询对应版本的官方Issue,确认是否存在已知的ThreadLocal内存泄漏缺陷,比如旧版本Netty的对象回收器、Jackson的JsonFactory复用逻辑都曾出现过类似问题;如果是自研组件,检查业务代码中使用完编解码器后是否主动调用ThreadLocal.remove()方法清理上下文,避免大对象常驻。
  • 核查线程池配置:从线程转储中识别出大量WAITING线程所属的线程池,核对其核心线程数、最大线程数配置是否合理,是否存在核心线程数设置过高的问题。
  • 验证引用链路:在堆转储中选中一个占用内存较大的byte[]/char[]实例,反向查询其GC引用链,确认是否最终指向ThreadLocalMap中的编解码器对象,锁定泄漏链路。
  • 对照验证:在测试环境调整线程池核心线程数,或者临时禁用编解码器的ThreadLocal复用逻辑,观测堆内存增长速率是否出现明显下降,验证根因判断是否正确。

内容的提问来源于stack exchange,提问作者Marcin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 02:45:01