核心是确认本该被回收的对象是否因被集合意外持有而滞留;典型表现包括堆内存持续上涨、FGC后回落不明显、jmap -histo显示业务类实例数激增、MAT中集合类Retained Heap占比高,定位需依次执行jps/jmap/MAT分析,重点检查static字段、ThreadLocal、监听器等强引用源头。

排查集合类引起的内存泄漏,核心是确认“本该被回收的对象,是否因被集合意外持有而滞留”。这类问题隐蔽但高频,尤其在静态集合、缓存、监听器注册等场景中极易发生。
一、快速识别集合类泄漏的典型表现
出现以下现象时,应优先怀疑集合类泄漏:
- 应用长时间运行后,堆内存持续缓慢上涨,Full GC 后内存回落不明显;
- 使用
jmap -histo <pid>对比不同时间点的输出,发现某自定义类(如User、Order)或其包装类(如ArrayList$Node、HashMap$Node)的实例数和内存占比异常增长; - 堆转储中,Histogram 显示
java.util.ArrayList、java.util.HashMap或java.util.concurrent.ConcurrentHashMap占用内存靠前,且其elementData或table字段引用了大量业务对象; - 应用无明显高并发或大数据量操作,却频繁触发老年代 GC。
二、定位泄漏源头的实操步骤
按顺序执行,避免盲目分析:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
查进程与堆状态:用
jps获取 PID,再执行jmap -heap <pid>看老年代使用率是否持续攀升; -
抓快照对比:在低峰期执行两次
jmap -histo <pid> > histo_1.txt(间隔 5–10 分钟),用diff histo_1.txt histo_2.txt找出激增的类; -
生成堆转储:执行
jmap -dump:live,format=b,file=heap.hprof <pid>(加live可过滤已标记为可回收的对象,更聚焦); -
用 MAT 分析 Dominator Tree:打开 heap.hprof → 打开 Dominator Tree → 按 “Retained Heap” 降序排列 → 展开占用最大的集合类(如
static ArrayList),右键 “Path to GC Roots” → 勾选 “exclude weak/soft references”,查看谁在强引用它; -
重点检查引用链起点:常见泄漏源头包括:
static字段、单例 Bean、未注销的监听器、线程局部变量(ThreadLocal)中的集合、缓存未设 size limit 或 TTL。
三、典型集合泄漏代码与修复方式
无需复现全部逻辑,抓住模式即可快速判断:
立即学习“Java免费学习笔记(深入)”;
-
静态集合累积:如
private static List<User> cache = new ArrayList<>();→ 改为使用ConcurrentHashMap+ 定时清理,或直接替换为Caffeine等带自动驱逐的缓存; - HashMap 键未重写 equals/hashCode:导致重复 put、无法 remove → 检查 key 类是否正确定义了这两个方法;
-
监听器注册后未反注册:如
eventBus.register(this)后未调用unregister()→ 在对象销毁生命周期(如 Spring 的@PreDestroy)中补全反注册; -
ThreadLocal 中的集合未清理:尤其在线程池场景下,线程复用导致旧数据残留 → 使用
threadLocal.remove(),避免仅设为null; -
Guava Cache 未配置最大容量或过期策略:如
CacheBuilder.newBuilder().build()→ 至少加上.maximumSize(1000)或.expireAfterWrite(10, TimeUnit.MINUTES)。
四、预防比排查更重要
在编码和设计阶段建立习惯,能大幅降低此类问题发生概率:
- 避免无明确生命周期管理的
static集合,必须使用时加上注释说明清理机制; - 所有缓存统一走封装好的缓存工具类,禁止直接 new HashMap/ArrayList 存全局数据;
- 在 IDE 中启用 FindBugs / SpotBugs 插件,关注
MS_MUTABLE_COLLECTION_PKGPROTECT、SE_BAD_FIELD_INNER_CLASS等告警; - CI 流程中加入内存基线测试:用 JMeter 跑 30 分钟稳定流量,监控
Old Gen Used是否线性增长; - 上线前检查 JVM 参数,确保开启
-XX:+HeapDumpOnOutOfMemoryError和合理 GC 日志(如-Xlog:gc*:file=gc.log)。

















