JavaプロセスがOOMで落ちる典型パターン【原因・確認・対処を完全整理】

  • URLをコピーしました!

Linuxサーバー上で稼働しているJavaアプリケーションが、 突然終了し、ログを見ると OutOfMemoryErrorOOM Killer が発動していた──。

Javaは「ヒープサイズを指定しているから安全」と思われがちですが、 実務では非常にOOMを起こしやすいアプリです。

本記事では、

  • JavaプロセスがOOMで落ちる典型パターン
  • OS視点・JVM視点の切り分け方法
  • 即効性のある対処策

を体系的に解説します。

目次

まず結論:JavaのOOMには2種類ある

  • JVM内のOOM(Java例外)
  • OS側のOOM Killerによる強制終了

この切り分けを間違えると、永久に原因が特定できません

パターン① -Xmx が物理メモリを超えている

典型例

  • サーバー:8GBメモリ
  • Java起動オプション:-Xmx8g

一見問題なさそうですが、これはほぼ確実にOOM Killer案件です。

理由

  • OS自身の使用メモリ
  • Metaspace
  • Thread Stack
  • Direct Memory

→ JVMヒープ以外にも大量にメモリを消費します。

確認方法

ps aux | grep java

対処

  • Xmxは物理メモリの60〜70%まで
-Xms4g -Xmx4g

パターン② コンテナ環境でメモリ上限を誤解している

症状

  • Docker / Kubernetes 上で突然Javaが終了
  • JavaログにOOMが残らない

原因

古いJavaや設定不備により、 コンテナのメモリ制限を認識できていない

確認

docker inspect <container> | grep Memory

対処

  • Java 8u191以降を使用
  • もしくは明示指定
-XX:+UseContainerSupport

パターン③ Direct Memory(NIO)が枯渇

特徴

  • Heapには余裕がある
  • OOMが突然発生

原因

  • Netty
  • Kafka Client
  • NIOベース通信

→ ヒープ外メモリを大量消費

確認

jcmd <PID> VM.native_memory summary

対処

-XX:MaxDirectMemorySize=512m

パターン④ Metaspace枯渇

典型ログ

java.lang.OutOfMemoryError: Metaspace

原因

  • クラスの動的生成
  • クラスローダリーク

対処

-XX:MaxMetaspaceSize=256m

※ 同時にアプリの設計見直しが必須です。

パターン⑤ スレッド数過多(Stackメモリ枯渇)

原因

  • 大量スレッド生成
  • ThreadPool無制限

確認

jstack <PID> | wc -l

対処

  • スレッドプール上限設定
  • Stackサイズ縮小
-Xss256k

パターン⑥ GCが追いつかない(メモリリーク)

兆候

  • Full GCが頻発
  • ヒープ使用率が下がらない

確認

jstat -gc <PID> 1000

対処

  • Heap Dump取得
  • MAT / VisualVMで解析

パターン⑦ OS側OOM Killerで強制終了

特徴

  • Javaログが残らない
  • プロセスが突然消える

確認

dmesg | grep -i oom

対処

  • Swap追加
  • MemoryMax設定(systemd)
  • oom_score_adj調整

実務での切り分けフロー

  1. Javaログに OutOfMemoryError があるか
  2. dmesg に OOM Killer があるか
  3. Xmx / Metaspace / Direct Memory確認
  4. コンテナ制限有無

JVMかOSかを最初に分けるのが最大のポイントです。

まとめ

  • JavaのOOMは「ヒープ不足」だけではない
  • JVM外メモリが原因のケースが多い
  • コンテナ環境は特に要注意
  • ログ・dmesg・JVM統計の三点で切り分け

Java OOMを正しく理解すると、 「原因不明で落ちるJava障害」から卒業できます。

目次