Linuxサーバー上で稼働しているJavaアプリケーションが、 突然終了し、ログを見ると OutOfMemoryError や OOM 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調整
実務での切り分けフロー
- Javaログに OutOfMemoryError があるか
- dmesg に OOM Killer があるか
- Xmx / Metaspace / Direct Memory確認
- コンテナ制限有無
→ JVMかOSかを最初に分けるのが最大のポイントです。
まとめ
- JavaのOOMは「ヒープ不足」だけではない
- JVM外メモリが原因のケースが多い
- コンテナ環境は特に要注意
- ログ・dmesg・JVM統計の三点で切り分け
Java OOMを正しく理解すると、 「原因不明で落ちるJava障害」から卒業できます。
あわせて読みたい


OOM Killer詳細|Linuxメモリ枯渇時の挙動・調査・対処を完全解説
Linuxサーバーで突然プロセスが落ちる/サーバーが不安定になる原因として非常に多いのが OOM Killer(Out Of Memory Killer)です。 本記事では、OOM Killerの仕組み・…
あわせて読みたい


LinuxのOOM Killerが発動する条件と回避策【実務での完全理解】
Linuxを運用していると、ある日突然アプリケーションが終了し、 ログを確認すると OOM Killer が動いていた── という経験をした方も多いのではないでしょうか。 OOM Kil…
