如何排查容器内存溢出(OOM)根本原因?Micronaut批量任务触发137退出码
退出码137本质是进程被操作系统的OOM Killer强制终止,通常是进程占用内存超过了cgroup限制。你没有生成JVM堆转储,说明OOM发生在JVM堆外或者操作系统层面,而非JVM堆内存溢出,可以按以下方向排查:
- 修复JDBC ResultSet全量拉取问题
你当前的代码没有设置fetchSize,绝大多数JDBC驱动默认会一次性将全部50万条查询结果加载到进程内存中,哪怕你按100条批次消费,这部分内存占用会直接打满容器。修复方式:
- 执行查询前设置statement的拉取批次大小:
statement.setFetchSize(batchSize);
- 如果你使用的是MySQL驱动,需要额外在JDBC连接URL中添加参数
useCursorFetch=true,否则fetchSize配置不生效。
- 调整JVM内存配置,避免超出容器限制
容器512M内存需要同时覆盖JVM堆、JVM元空间、堆外内存、操作系统进程基础开销,不能将JVM堆设得过高:
- 添加JVM参数指定堆上限:
-Xmx384m -Xms384m,预留128M给堆外内存和系统开销 - 显式限制堆外内存上限:
-XX:MaxDirectMemorySize=64m,如果后续出现堆外内存OOM会抛出明确报错,方便定位
- 排查业务逻辑内存泄漏
- 检查
consumer.accept的处理逻辑:是否有全局静态集合持有了所有批次的ItemEntity对象未释放,API调用的HTTP客户端是否存在连接未关闭、请求/响应体资源未释放的问题 - 检查SQLite写入逻辑:是否存在批量写入缓存未按时提交、驱动资源未释放的问题
实时监控内存变化定位峰值
运行批量任务的同时执行docker stats <容器ID>,观察容器内存占用的变化曲线:如果拉取数据阶段内存直接飙升到512M,就可以确认是ResultSet全量拉取的问题;如果内存是在处理批次过程中缓慢上涨,就是业务逻辑存在内存泄漏。临时放大容器内存验证根因
可以先将容器内存限制调整到1G,如果任务可以正常运行,说明问题本质就是内存不足,再针对性做内存优化即可。
内容的提问来源于stack exchange,提问作者Manish
相关产品推荐
相关产品推荐

