单元测试变慢很可能是内存泄漏所致,需通过jvm gc日志分析异常、主动导出堆快照,并用mat的dominator tree和leak suspects定位静态缓存、未清理mock、未关闭资源等泄漏点。

单元测试运行时间越来越长,尤其是反复执行后明显变慢,很可能是内存泄漏在作祟——不是代码逻辑慢,而是堆里对象越积越多,GC压力飙升,导致每次测试都卡在垃圾回收上。
看GC行为是否异常
给测试 JVM 加上这些参数运行:
- -XX:+PrintGCDetails -XX:+PrintGCTimeStamps:输出每次 GC 的类型、耗时、前后内存变化
- -Xlog:gc*:file=gc.log:time(JDK 11+)或 -Xloggc:gc.log(旧版):把日志存到文件方便分析
重点观察:
— 是否出现频繁的 Full GC 或长时间的 CMS/G1 Mixed GC
— 每次 Minor GC 后老年代占用是否阶梯式上升
— GC 总耗时是否随测试轮次持续增长
抓取测试过程中的堆快照
不要等 OOM 才行动。在测试执行中主动导出堆内存快照:
- 用 jps 查到测试进程 PID
- 执行 jmap -dump:format=b,file=test-heap.hprof
(建议在测试跑完但进程未退出时立即执行) - 如果用 Maven Surefire,可加 -DforkMode=never 避免 fork 新进程,方便直接监控主 JVM
这样能捕获“正在变慢”阶段的真实堆状态,比崩溃后 dump 更有诊断价值。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
用 MAT 定位泄漏源头
把 hprof 文件拖进 MAT,重点关注:
- 打开 Dominator Tree,按 “Retained Heap” 降序,找长期存活且数量激增的对象(比如某测试类的实例、Mock 对象、静态缓存 Map)
- 点开可疑对象 → 右键 Path to GC Roots → 勾选 “exclude weak/soft references”,看是谁强引用着它不让 GC
- 检查 Leak Suspects Report,MAT 会自动标出最可能泄漏的组件(如静态集合、线程局部变量、未关闭的 Closeable 资源)
常见泄漏点:@Before 中 new 出的大型对象未清理、静态 Map 缓存了测试数据、Mockito 的 mock 对象未 reset、数据库连接池未 shutdown、Logback 的 LoggerContext 没 stop。
结合测试生命周期做代码审查
单元测试本身是短生命周期的,但以下写法会让对象意外“活过一轮测试”:
- 使用 static 字段 存放 List/Map/Cache —— 它们跨测试方法累积
- @BeforeClass 初始化的资源未在 @AfterClass 中释放
- 使用 ThreadLocal 但没调用 remove(),尤其在线程复用场景(如 Spring TestContext)
- 第三方库(如 HikariCP、Elasticsearch RestClient)创建的客户端未 close()
建议:所有测试类尽量无状态;必须共享资源时,用 try-with-resources 或显式 teardown;静态变量优先考虑 WeakHashMap 或 AtomicReference。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










