Gradlew运行大量测试时OutOfMemoryError的配置优化求助
解决测试阶段OutOfMemoryError及GCLocker警告的配置优化
我维护的应用包含500-700个测试用例,执行./gradlew clean build时部分测试会启动Spring上下文,多次调整build.gradle的测试配置后,仍频繁出现OutOfMemoryError,日志中有GCLocker相关警告,且多线程抛出内存不足异常。当前test配置如下:
test { useJUnitPlatform() maxParallelForks = 1 forkEvery = 10 jvmArgs = [ '-Xmx2g', '-XX:MaxMetaspaceSize=512m', '-XX:+UseG1GC', '-XX:G1HeapRegionSize=8m', '-XX:InitiatingHeapOccupancyPercent=20', '-XX:ConcGCThreads=1', '-XX:ParallelGCThreads=1', '-XX:MaxGCPauseMillis=300', '-XX:+HeapDumpOnOutOfMemoryError', '-XX:HeapDumpPath=build/heapdumps', '-Xlog:gc*:build/gc.log' ] systemProperties = [ "feign.client.config.default.connectTimeout" : "5000", "feign.client.config.default.readTimeout" : "5000", "feign.httpclient.maxConnections" : "3", "hikari.maximumPoolSize" : "2" ] }
核心优化方案
1. 调整GC配置,缓解GCLocker阻塞
GCLocker警告多与JNI代码阻塞GC有关,当前GC线程数过低会直接拖慢回收效率:
- 移除
-XX:ConcGCThreads=1和-XX:ParallelGCThreads=1,让JVM根据CPU核心自动分配线程数;若需手动设置,建议设为CPU核心数的1/2(比如4核机器设为2) - 暂时切换到并行GC组合:
-XX:+UseParallelGC+-XX:+UseParallelOldGC,并行GC在批量测试场景下的内存回收效率更稳定,能减少GCLocker触发概率
2. 强化测试进程隔离,避免内存积累
当前配置的进程隔离策略不足以应对上下文启动类测试的内存开销:
- 提升
maxParallelForks到CPU核心数的1/2(需确保机器内存充足,比如2个进程配Xmx2g,需预留至少4g+系统内存) - 降低
forkEvery值至5,更频繁重启JVM进程,减少单个进程内的内存泄漏积累 - 可选添加
forkMode = "perTest",强制每个测试类启动独立进程,彻底隔离上下文内存(若测试执行时间可接受)
3. 精细化内存参数调整
- 添加
-Xms2g,让JVM初始堆等于最大堆,避免堆扩容带来的额外GC压力 - 将
-XX:InitiatingHeapOccupancyPercent调回默认值45,当前20的阈值会导致GC过于频繁,反而加剧CPU和内存开销 - 移除
-XX:MaxGCPauseMillis=300,测试场景下无需严格的暂停时间限制,强制目标会导致G1优先回收小区域,加剧内存碎片化
4. 测试代码辅助优化
- 对启动Spring上下文的测试类,添加
@DirtiesContext注解,标记测试后销毁上下文,避免上下文复用导致的内存泄漏 - 在测试类的
@AfterAll方法中手动关闭Feign连接池和Hikari数据源,确保资源及时释放
优化后的示例配置
test { useJUnitPlatform() maxParallelForks = 2 forkEvery = 5 forkMode = "perTest" // 可选,按测试类隔离进程 jvmArgs = [ '-Xms2g', '-Xmx2g', '-XX:MaxMetaspaceSize=512m', '-XX:+UseParallelGC', '-XX:+UseParallelOldGC', '-XX:+HeapDumpOnOutOfMemoryError', '-XX:HeapDumpPath=build/heapdumps', '-Xlog:gc*,gc+heap=debug:file=build/gc.log:time,uptime:filecount=5,filesize=10m' ] systemProperties = [ "feign.client.config.default.connectTimeout" : "5000", "feign.client.config.default.readTimeout" : "5000", "feign.httpclient.maxConnections" : "3", "hikari.maximumPoolSize" : "2" ] }
内容的提问来源于stack exchange,提问作者Назар
相关产品推荐
相关产品推荐

