不能自救。OutOfMemoryError 是 JVM 资源彻底枯竭的不可恢复错误,捕获后继续运行极危险;正确做法是立即摘流、禁用内存敏感操作、自动堆转储并精简日志;预防优于捕获,需压测监控、杜绝内存泄漏、流式处理大数据。

不能自救。OutOfMemoryError 是 Error,不是 Exception,它代表 JVM 资源已彻底枯竭,程序处于不可恢复状态,不应也不可被 try-catch 捕获后继续运行。
为什么 catch 无效且危险
捕获 OutOfMemoryError 并试图“兜底”或“重试”,会掩盖系统真实故障,带来更严重后果:
- JVM 可能已无法安全分配新对象,连日志、异常堆栈、甚至 catch 块内的简单变量声明都可能再次触发 OOM
- GC 已频繁失败或长时间 STW,线程调度紊乱,对象引用关系可能已损坏,继续执行逻辑极易引发数据不一致或静默错误
- 常见“补救”操作如写数据库、发消息、调用远程服务,本身依赖内存和线程资源,大概率失败并阻塞整个流程
正确的响应动作是“止血+留痕”
发现 OOM 后,系统应立即放弃业务逻辑,转向运维可观测性与故障隔离:
- 通过负载均衡器或服务注册中心,秒级摘除该节点,防止流量继续涌入
- 禁止在 catch 或 finally 中执行任何内存敏感操作(如 new 对象、拼接字符串、DB 写入、日志输出)
- 确保 JVM 启动时已配置
-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath,让崩溃前自动保存关键线索 - 记录原始错误日志(仅限 Throwable.toString()),避免格式化或附加上下文——此时连 StringBuilder 都可能分配失败
区分“能捕获”和“该捕获”
语法上,catch (OutOfMemoryError e) 是合法的,但语义上完全违背 JVM 规范的设计意图:
- Exception 表示程序可预期、可恢复的异常情况(如 IOException、SQLException),设计上支持被捕获并处理
- Error(包括 OutOfMemoryError、StackOverflowError、NoClassDefFoundError)表示虚拟机级严重故障,JVM 规范明确将其定义为“不推荐捕获”的不可恢复错误
- 试图用 catch 包裹 OOM,就像给即将坍塌的大楼装窗帘——动作做了,但问题本质没变,反而延误疏散
真正可靠的方案是预防而非捕获
把精力放在让 OOM 少发生、早发现、快定位上,比写一个 catch 块有效百倍:
- 压测阶段监控老年代使用率(OU)、Full GC 频次、对象晋升速率,识别内存泄漏苗头
- 代码中杜绝无界缓存(如 HashMap/ArrayList 无限 add)、静态集合持有业务对象、ThreadLocal 未 remove
- 对大文件、大数据集采用流式处理(InputStream / ResultSet 分页读取),避免
readAllBytes或listAll() - 上线后配置 APM 工具告警,对
java.lang.OutOfMemoryError关键字实时推送,触发应急 SOP










