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

Java中Groovy执行器内存限制实现方法咨询

Groovy脚本内存限制实现方案

针对你在Java环境中运行Groovy脚本时的内存限制需求,以下是几种可行的实现方式,结合你已有的代码框架:


方式一:线程内存监控+中断(简单直接)

将脚本执行逻辑放到单独线程中,启动监控线程定时检查堆内存占用,达到阈值时中断脚本线程:

示例代码:

// 执行脚本的线程
Thread scriptThread = new Thread(() -> {
    try {
        // 执行Groovy脚本逻辑,例如调用脚本的执行方法
        groovy.invokeMethod("execute", null);
    } catch (InterruptedException e) {
        throw new RuntimeException("脚本内存占用超过阈值", e);
    }
});

// 内存监控线程
Thread monitorThread = new Thread(() -> {
    long memoryThreshold = 1024 * 1024 * 50; // 设置50MB内存阈值
    while (scriptThread.isAlive()) {
        // 计算当前已使用堆内存
        long usedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        if (usedMemory >= memoryThreshold) {
            scriptThread.interrupt();
            break;
        }
        try {
            Thread.sleep(100); // 每100ms检查一次内存
        } catch (InterruptedException ignored) {}
    }
});

// 启动线程
scriptThread.start();
monitorThread.start();

// 等待脚本执行完成
try {
    scriptThread.join();
    monitorThread.interrupt();
    monitorThread.join();
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

方式二:通过Groovy Sandbox拦截内存相关操作(精准控制)

利用已集成的groovy-sandbox自定义拦截器,监控脚本中的变量赋值、对象创建、集合添加等操作,累计内存占用,达到阈值时终止脚本:

示例代码:

// 自定义内存监控拦截器
class MemoryLimitInterceptor extends SandboxInterceptor {
    private final long memoryThreshold;
    private long initialUsedMemory;

    public MemoryLimitInterceptor(long memoryThreshold) {
        this.memoryThreshold = memoryThreshold;
        // 记录脚本执行前的内存占用
        this.initialUsedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }

    @Override
    public Object onSetProperty(GroovyObject obj, String property, Object value) throws Throwable {
        checkMemoryLimit();
        return super.onSetProperty(obj, property, value);
    }

    @Override
    public Object onNewInstance(Constructor c, Object[] args) throws Throwable {
        checkMemoryLimit();
        return super.onNewInstance(c, args);
    }

    @Override
    public Object onMethodCall(Object receiver, String method, Object[] args) throws Throwable {
        // 拦截集合的add/addAll操作,防止无限扩容
        if (receiver instanceof Collection && ("add".equals(method) || "addAll".equals(method))) {
            checkMemoryLimit();
            Collection coll = (Collection) receiver;
            if (coll.size() >= 10000) { // 限制集合最大元素数
                throw new RuntimeException("集合大小超过限制");
            }
        }
        return super.onMethodCall(receiver, method, args);
    }

    private void checkMemoryLimit() {
        long currentUsed = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        long scriptUsed = currentUsed - initialUsedMemory;
        if (scriptUsed >= memoryThreshold) {
            throw new RuntimeException("脚本内存占用超过阈值");
        }
    }
}

// 替换原有SandboxInterceptor注册逻辑
// 注释掉 new SandboxInterceptor().register();
new MemoryLimitInterceptor(1024 * 1024 * 50).register(); // 传入50MB阈值

方式三:结合SecureASTCustomizer限制危险操作(提前预防)

通过SecureASTCustomizer禁止或限制可能导致内存泄漏的操作,比如禁止无限循环、限制集合初始化大小:

示例代码:

final SecureASTCustomizer secure = new SecureASTCustomizer();
// 保留你原有的配置...

// 禁止while循环,防止无限循环赋值
secure.setTokensBlacklist(concatList(new Integer[0], TOKEN_BLACK_LIST, TokenType.WHILE));

// 限制集合初始化的元素数量
secure.addExpressionCheckers(expression -> {
    if (expression instanceof ConstructorCallExpression) {
        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
        if ("java.util.ArrayList".equals(cce.getType().getName()) && cce.getArguments() != null) {
            if (cce.getArguments().size() > 1000) {
                throw new RuntimeException("集合初始化元素过多");
            }
        }
    }
    return true;
});

注意事项

  • 线程中断方式需要脚本代码能响应中断,比如在循环中主动检查Thread.currentThread().isInterrupted(),否则无法及时终止
  • Sandbox拦截方式需覆盖所有可能消耗内存的操作(如数组创建、字符串拼接等),才能做到精准监控
  • 内存阈值需根据JVM堆大小调整,避免误判

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:57:15