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

如何增大Spock Framework堆内存 解决Gradle测试Java堆溢出问题

问题原因
  • 你之前配置的GROOVY_OPTS、gradlew脚本里的DEFAULT_JVM_OPTS都不会作用于Gradle的测试进程:GROOVY_OPTS仅对groovy命令直接启动的Groovy程序生效,DEFAULT_JVM_OPTS仅对Gradle主进程以及run这类继承Gradle JVM参数的任务生效,而test任务默认会fork独立的JVM进程执行测试,有自己独立的JVM参数配置,默认堆内存通常只有512M,所以你之前的内存配置完全没生效。
  • 你的代码本身初始化时就会占用大量内存:new BitSet(Integer.MAX_VALUE)会在初始化时直接分配足够存储2^31-1位的底层long数组,单个BitSet初始化就占256MB,两个BitSet加起来固定占512MB,再算上JVM基础开销、Spock框架的内存占用,很容易打满测试进程默认的堆内存触发OOM。
  • 你执行./gradlew run能正常运行,是因为run任务拿到了你配置的2G堆内存,足够支撑这两个BitSet的初始化开销。
解决方案

方案1:给测试进程配置足够堆内存(快速修复)

在项目的build.gradle中为test任务单独配置JVM内存参数,和你run任务的内存规格对齐:
如果使用Groovy DSL(默认的build.gradle格式):

test {
    // 给测试进程分配2G堆内存
    maxHeapSize = "2048m"
    // 避免同时fork多个测试进程占满本机内存,可根据机器实际内存调整
    forkEvery = 1
}

如果使用Kotlin DSL(build.gradle.kts格式):

tasks.test {
    maxHeapSize = "2048m"
    forkEvery = 1
}

方案2:优化BitSet初始化逻辑(根本优化,推荐)

你当前给BitSet构造传Integer.MAX_VALUE是完全没必要的:BitSet本身支持动态扩容,无参构造默认只初始化64位的极小空间,后续调用set()方法存储数据时会根据需要自动扩容,不会影响功能。去掉构造参数后,初始化阶段内存占用从固定512MB降到几字节,只有当你真的存储接近全量int值的时候才会逐步扩容到最大内存,平时跑测试、处理少量IP数据的时候内存压力会极小:

public class IntSet {
    // 移除BitSet构造的Integer.MAX_VALUE参数,使用默认无参构造
    private final BitSet[] storage = {new BitSet(), new BitSet()};

    public void add(int i) {
        if (i >= 0) {
            storage[0].set(i);
        } else {
            storage[1].set(-++i);
        }
    }

    public long size() {
        return (long) storage[0].cardinality() + storage[1].cardinality();
    }
}

优化后哪怕测试进程用默认的512M堆也能正常运行,不需要额外调大内存。

内容的提问来源于stack exchange,提问作者Jegors Čemisovs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 16:01:17