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

Java捕获OutOfMemoryError后程序仍可继续运行的原因咨询

为什么测试中OOM被捕获后仍能正常运行

你遇到的是非常特殊的温和OOM场景,核心原因是:
你触发OOM的操作是尝试分配new Integer[10000000 * 10000000]这个超大数组,这个数组的总大小远超过你设置的1MB堆上限,JVM在分配前检查到空间不足直接抛出OutOfMemoryError,这个数组自始至终都没有分配成功,也没有占用任何堆内存。
所以异常被catch之后,堆可用空间和执行test方法前几乎没有差别,后续你只需要分配100个int的小数组,完全在可用空间范围内,自然可以正常执行。加上ScheduledExecutorService按固定频率调度任务,每次执行前之前的临时对象都已经被GC回收,所以会反复输出相同的日志。


这个测试结果不具备普遍性

不要觉得所有OOM被捕获后都能正常运行,生产环境的绝大多数OOM场景捕获后都无法正常执行业务:

  • 如果是内存泄漏累积导致的OOM:整个堆几乎被存活对象占满,随便分配小对象都会触发OOM,就算捕获了异常,后续只要有对象分配操作还是会反复抛异常,根本跑不动。
  • 如果OOM发生在JVM核心流程:比如GC、类加载、线程创建阶段抛出OOM,就算捕获了,JVM内部状态已经被破坏,后续大概率会出现逻辑错乱、未知崩溃的问题。

关于是否应该捕获Throwable的说明

工业界普遍不建议随意捕获Throwable:
Error类型的异常本身就是用来标识「程序正常运行时不应该出现的严重问题」,大部分Error出现后程序状态已经不可控,强行继续运行很容易出现数据损坏、逻辑不一致的问题。
只有少数特定场景可以做有限捕获:比如需要上报错误日志、避免单个任务异常拖垮整个服务时,可以在任务最外层入口捕获Throwable,完整记录错误栈、内存快照后,要么主动优雅退出进程,要么丢弃异常任务做降级,绝对不能吞掉异常后当做什么都没发生继续执行业务。


你测试用的代码和运行命令供参考:

public class TestErrorInThread {
    public static void test() {
        System.out.println("Running the test at time " + new Date());
        try {
            System.out.println("Inside try block");
            Integer[] array = new Integer[10000000 * 10000000];
        } catch (Throwable e) {
            System.out.println("Inside catch block");
            System.out.println(e);
        }
        int arr[] = new int[100];
        System.out.println("Programme is still running...");
    }

    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        Runnable runnable = TestErrorInThread::test;
        scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 5, TimeUnit.SECONDS);
    }
}

运行命令:

java -Xmx1m TestErrorInThread

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 02:57:04