一、问题现象

常见现象:

  • Docker 容器运行一段时间后自动重启

  • docker ps 查看:

docker ps

发现:

STATUS: Up 几分钟

但是:

CREATED: 几天前

说明:

容器不是新创建,而是运行期间发生过重启。


二、第一步:确认容器是否重启过

查看重启次数:

docker inspect self_service | grep -A10 RestartCount

示例:

"RestartCount": 6

说明:

  • 容器已经异常退出并被 Docker 自动拉起多次。

如果:

"RestartCount": 0

说明:

可能是:

  • Docker服务重启

  • 宿主机重启

  • 人工启动


三、第二步:查看容器状态

执行:

docker inspect self_service | grep -A20 State

重点关注:

1. ExitCode

例如:

"ExitCode": 137

表示:

容器收到:

SIGKILL

通常原因:

  • 内存不足

  • OOM Killer杀进程


2. OOMKilled

例如:

"OOMKilled": true

表示:

Docker确认发生OOM。

注意:

部分 Docker/containerd 版本可能显示:

"OOMKilled": false

但实际发生OOM。

需要结合:

docker events

判断。


四、第三步:查看 Docker 事件(最关键)

执行:

docker events --since 24h

重点关注:


OOM

例如:

container oom self_service

说明:

容器发生内存不足。


容器退出

例如:

container die
exitCode=137

说明:

进程被强制杀死。


自动恢复

例如:

container start

说明:

Docker根据restart策略自动启动。


五、判断OOM完整链路

典型OOM流程:

Java进程内存增长
        |
        |
        v
超过Docker限制
        |
        |
        v
Linux OOM Killer执行kill -9
        |
        |
        v
容器退出(exitCode=137)
        |
        |
        v
Docker restart策略重新启动

六、第四步:查看容器日志

查看最近日志:

docker logs --tail=300 self_service

查看指定时间:

docker logs \
--since "2026-08-10 14:40:00" \
self_service

重点搜索:

Java Heap OOM

java.lang.OutOfMemoryError:
Java heap space

表示:

Java堆内存不足。


Metaspace不足

OutOfMemoryError:
Metaspace

表示:

类元空间不足。


DirectMemory不足

OutOfMemoryError:
Direct buffer memory

表示:

NIO堆外内存不足。


七、第五步:查看容器内存限制

执行:

docker inspect self_service | grep -i memory

例如:

"Memory": 2147483648

代表:

2GB限制。

换算:

2147483648 bytes ≈ 2GB

查看启动参数:

docker inspect self_service | grep Cmd -A10

检查:

--memory
--memory-swap

八、Java容器内存计算方法

注意:

Java实际占用:

Java总内存 =
Heap
+
Metaspace
+
DirectMemory
+
线程栈
+
CodeCache
+
Native Memory

不是只有:

-Xmx

例如:

配置:

-Xmx2048m
-XX:MaxMetaspaceSize=384m
-XX:MaxDirectMemorySize=512m

理论:

Heap:
2048M

Metaspace:
384M

Direct:
512M

其它:
300~600M


总计:
约3.2G~3.5G

因此:

4G容器比较合理。


九、检查宿主机是否整体内存不足

查看:

free -h

查看:

top

查看OOM记录:

journalctl -k | grep -i oom

或者:

dmesg | grep -i killed

如果出现:

Out of memory:
Killed process xxxx(java)

说明:

宿主机内核杀进程。


十、查看实时内存使用

执行:

docker stats self_service

观察:

例如:

MEM USAGE / LIMIT

3.8GiB / 4GiB

说明:

已经接近危险值。

建议:

使用情况 判断
<60% 正常
60%-80% 观察
80%-90% 风险
>90% 容易OOM

十一、Java容器推荐配置示例

Docker限制

--memory=4g
--memory-swap=4g

JVM

推荐:

-Xms1024m
-Xmx2048m
-XX:+UseContainerSupport
-XX:+ExitOnOutOfMemoryError
-XX:MaxMetaspaceSize=384m
-XX:MaxDirectMemorySize=512m

内存预算:

Heap          2G
Metaspace     384M
Direct        512M
Native        300~600M

总计约3.2G~3.5G

4G容器安全

十二、常见错误配置

错误1

容器:

--memory=2g

JVM:

-Xmx2048m

问题:

Heap已经接近容器上限。

其它内存没有空间。


错误2

-Xms2304m
-Xmx2048m

错误:

Xms必须 <= Xmx

正确:

-Xms1024m
-Xmx2048m

错误3

Docker启动参数传递JVM参数

错误:

docker run xxx \
--add-opens=java.base/java.lang=ALL-UNNAMED

因为:

ENTRYPOINT已经启动:

java -jar app.jar

后面的参数会作为Spring Boot参数。

JVM参数应该放:

Dockerfile ENTRYPOINT。


十三、排查顺序总结

遇到容器自动重启:

按照顺序:

1. docker ps
        |
        v
确认Up时间异常

2. docker inspect
        |
        v
查看RestartCount

3. docker inspect State
        |
        v
查看ExitCode

4. docker events
        |
        v
确认OOM / die

5. docker logs
        |
        v
查看Java异常

6. docker stats
        |
        v
观察实时内存

7. 检查JVM参数
        |
        v
调整-Xmx、Metaspace、DirectMemory

8. 检查代码是否存在内存泄漏

十四、关键判断口诀

ExitCode 137
+
docker events出现oom
=
内存杀进程

OOMKilled=false
不要急着否定OOM

优先相信:
docker events

十五、本次问题总结

问题原因:

容器限制:
2GB

JVM:
-Xmx2048m
+
Metaspace 400M
+
DirectMemory 1024M

实际需求:
超过3GB

结果:
OOM Killer杀死Java

exitCode=137

Docker restart自动恢复

解决:

容器:
2G → 4G

降低DirectMemory:
1024M → 512M

合理控制Heap:
-Xmx2048m

删除重复JVM参数

更多推荐