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

Docker容器低负载时以137码退出,高负载正常的Java应用问题求助

解决Docker容器中Java应用以退出码137退出的问题

首先咱们得把问题的本质拎清楚:退出码137(128+9)是Docker的OOM Killer(内存不足杀手)直接终止了你的Java进程,但JVM日志没报堆或元空间OOM,说明问题出在JVM进程的总内存占用超出了容器2GB的限制——而非你配置的堆内存本身不足。

核心原因:JVM的内存不止堆内存

你用-Xmx1024m限制了堆内存,但JVM的整体内存占用还包含这些堆外部分:

  • 每个线程的栈内存(你设了-Xss256k,线程数量越多,总栈内存越高)
  • 元空间(Metaspace,存储类元数据,默认无上限,只会受容器内存限制)
  • 直接内存(Direct Memory,NIO等场景会用到,默认和-Xmx值一致)
  • JVM自身的进程开销(比如JNI调用、JIT编译的代码缓存、GC后台线程等)

至于「无负载时出问题、有负载时正常」的现象也很好解释:无负载时堆内存实际占用很低,但堆外内存(比如代码缓存、元空间、后台线程栈)的占比相对更高,总和刚好触碰到容器2GB的内存上限;而有负载时堆内存占用上升,JVM会自动调整堆外某些区域的分配,或者负载带来的CPU占用让OOM Killer暂时不会优先杀你的进程。

具体排查与解决步骤

1. 先确认JVM的实际总内存占用

  • 用docker stats查看容器的实时内存占用,看是不是接近或超过2GB;
  • 进入容器,用ps aux查看Java进程的RSS(Resident Set Size)列,这是进程实际占用的物理内存(包含堆和堆外所有部分);
  • 开启JVM本地内存追踪:启动时加参数-XX:NativeMemoryTracking=summary,之后用jcmd <进程ID> VM.native_memory summary命令,能精准看到JVM各个内存区域的详细占用(堆、元空间、直接内存、代码缓存等),快速定位哪个堆外区域占用过高。

2. 调整JVM参数,限制总内存不超过容器上限

推荐用自动适配容器内存的参数代替手动设置-Xmx,这样JVM会自动平衡堆和堆外内存的分配,避免手动配置的盲区:

-XX:MaxRAMPercentage=75.0

这个参数会让JVM将总内存(堆+堆外)限制在容器可用内存的75%(2GB的75%是1.5GB),留足余量给堆外内存和JVM自身开销。

如果坚持手动配置,要把堆内存+预估的堆外内存严格控制在2GB以内,比如:

-Xmx1024m -Xms256m -Xss256k \
-XX:MaxMetaspaceSize=256m \
-XX:MaxDirectMemorySize=256m \
-XX:ReservedCodeCacheSize=128m

这里明确限制了元空间、直接内存、代码缓存的大小,避免它们无限制增长。

3. 确认容器的内存限制是否正确生效

用docker inspect <容器ID>查看HostConfig.Memory字段,确认值为2147483648(即2GB对应的字节数),避免启动容器时的内存限制参数写错(比如写成-m 2gb而非-m 2g,或者配置文件里的低级错误)。

4. 排查无负载时的特殊内存占用

无负载时退出,大概率是JVM的后台任务导致的:

  • 检查Code Cache(JIT编译的代码缓存)是否无限制增长,用上面的VM.native_memory命令查看,要是占比过高,就用-XX:ReservedCodeCacheSize限制;
  • 确认容器里只有Java进程在运行,用ps aux检查是否有其他后台进程偷偷占用内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:59:58