SwapがあるのにJavaがOOMで落ちる理由【よくある誤解と正しい理解】

  • URLをコピーしました!

「Swapは十分にあるのに、なぜかJavaプロセスがOOMで落ちる」
この現象は、Java × Linux 障害対応で非常によくある誤解です。

結論から言うと、

Swapがある=JavaがOOMにならない、ではありません。

本記事では、

  • SwapがあってもJavaがOOMになる理由
  • OSとJVMのメモリ管理の違い
  • 実務での正しい確認ポイントと対処策

を整理して解説します。

目次

まず結論:JavaはSwapを前提に動いていない

Linuxでは、

  • 物理メモリ(RAM)
  • Swap

を合わせて「利用可能メモリ」と見なしますが、 JVMはこの考え方を基本的に採用していません。

Javaは「物理メモリ前提」でヒープを確保します。

誤解① SwapがあればOOM Killerは発動しない

これは誤りです。

理由

  • LinuxのOOM KillerはSwap残量だけで判断しない
  • メモリ割当失敗やフラグメンテーションも考慮

そのため、

  • Swapが空いている
  • しかしRAMが逼迫している

という状況でも、OOM Killerは発動します。

確認コマンド

free -h

誤解② Javaは必要に応じてSwapを使ってくれる

これも誤りです。

理由

Javaは以下の領域を常駐メモリ(RSS)として使用します。

  • Java Heap
  • Metaspace
  • Thread Stack
  • Direct Memory

これらはSwapに追い出されると致命的な性能劣化を起こすため、 Linuxカーネルは積極的にSwapアウトしません。

典型パターン① ヒープサイズが物理メモリ限界まで指定されている

  • 物理メモリ:8GB
  • Swap:8GB
  • Java起動オプション:-Xmx8g

ほぼ確実にOOM Killer対象

なぜか

  • OS自身の使用メモリ
  • ヒープ外メモリ

を考慮していないためです。

対処

-Xms4g -Xmx4g

目安:Xmxは物理メモリの60〜70%

典型パターン② Direct MemoryがSwapに逃げない

Netty・NIO・Kafka Clientなどは Direct Memory(ヒープ外)を多用します。

この領域は、

  • ヒープサイズに含まれない
  • Swapに逃げにくい

ため、物理メモリを圧迫します。

確認

jcmd <PID> VM.native_memory summary

対処

-XX:MaxDirectMemorySize=512m

典型パターン③ systemd / cgroup によるメモリ制限

systemd管理のJavaサービスでは、 Swapがあってもメモリ制限によりOOMになることがあります。

確認

systemctl show <service> | grep Memory

MemoryMax=2G

→ この制限を超えた時点でOOM

典型パターン④ vm.swappiness の誤解

「swappinessを上げればJavaはSwapを使う」と思われがちですが、 これは限定的な効果しかありません。

確認

cat /proc/sys/vm/swappiness

注意点

  • Javaの主要メモリはSwap対象になりにくい
  • 無理にSwapさせるとGCやレスポンスが崩壊

OOM Killerが発動しているかの確認

Javaログに何も残らずプロセスが消える場合は、 OS側OOMを疑います。

確認

dmesg | grep -i oom

実務での正しい考え方

  • Swapは「最後の保険」でしかない
  • JavaはSwap前提で設計してはいけない
  • 物理メモリ内で完結する設計が必須

おすすめ設計指針

  • Xmxは物理メモリの60〜70%
  • Direct Memory / Metaspace を明示制限
  • systemd / cgroup の制限確認
  • SwapはOOM回避ではなくOS安定用

まとめ

  • SwapがあってもJavaは普通にOOMで落ちる
  • JVMは物理メモリ前提で動く
  • ヒープ外メモリが原因のケースが多い
  • OOMは「Swap不足」ではなく「設計ミス」

Swapに期待せず、 JavaとLinuxのメモリ設計を正しく理解することが 安定運用への近道です。

目次