java-oom

Java OutOfMemoryError 的定位与处理

现象

应用日志出现 java.lang.OutOfMemoryError(Java heap space、Metaspace、Direct buffer memory、unable to create native thread),进程可能退出或被容器 OOMKilled。

快速定位

jcmd <pid> GC.heap_info
jcmd <pid> VM.flags
jstat -gcutil <pid> 1000 10
jmap -histo:live <pid> | head -30
jcmd <pid> Thread.print | head -100

容器:

cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.current
dmesg -T | grep -i oom

常见根因

  1. 堆上限太小,业务峰值不够用。
  2. 内存泄漏:集合、缓存、监听器持续增长。
  3. Metaspace/类加载器泄漏(热部署、动态代理)。
  4. Direct buffer/NIO 或 native 内存超限。
  5. 线程数过多,栈内存耗尽。
  6. 容器 memory limit 低于 JVM 总内存(堆+元空间+直接内存+线程栈)。

修复

相关命令

读完自测

合上页面,先回答,再展开对照。

  1. 如何区分是哪一类 OutOfMemoryError?
  2. 容器 memory limit 与 JVM 各内存区域是什么关系?
  3. 保留现场和修复的常用做法有哪些?
答案
  1. 看错误信息(heap space、Metaspace、Direct buffer memory、unable to create native thread),并用 jcmd GC.heap_info、VM.flags、jstat 等确认。
  2. limit 必须覆盖堆、元空间、直接内存和线程栈,否则会被 OOMKilled;可查 cgroup 的 memory.max/memory.current 和 dmesg。
  3. 配置 -XX:+HeapDumpOnOutOfMemoryError 和 dump 路径,用堆快照/直方图找增长对象,调整 -Xmx、MaxMetaspaceSize、MaxDirectMemorySize 和线程池上限并修泄漏。