JVM ヒープサイズが実行中のコンテナのメモリ制限に対して大きすぎると、以下の 2 つの障害が発生します。Linux 環境では OOM Killer が Java プロセスを終了し、Docker コンテナではコンテナインスタンスが繰り返し再起動します。いずれの障害も、根本原因は「コンテナのメモリ制限を超えたこと」です。
OOM の 2 種類を理解する
ヒープサイズを構成する前に、2 種類の OOM 障害の違いを理解してください。それぞれに異なる対応が必要です。
| OOM の種類 | 発生条件 | 症状 | ヒープダンプの生成有無 |
|---|---|---|---|
| コンテナ OOM(終了コード 137) | コンテナ全体のメモリ使用量(ヒープ+非ヒープメモリ、システムライブラリ、その他のプロセス)がコンテナのメモリ制限を超え、OOM Killer によりコンテナが終了されます。 | コンテナが再起動;終了コード 137 | いいえ — JVM が独自の OOM ハンドラを起動することはありません |
JVM OOM(java.lang.OutOfMemoryError) | JVM ヒープが構成済みの最大値に達しました。 | アプリケーションが OutOfMemoryError をスロー;アプリケーションがエラーを適切に処理できない場合を除き、コンテナは再起動しません | はい — -XX:+HeapDumpOnOutOfMemoryError が有効になっている場合 |
非ヒープメモリ(Metaspace、スレッドスタック、ダイレクトメモリ、GC オーバーヘッド、システムコンポーネントなど)の確保を考慮し、JVM ヒープサイズはコンテナのメモリ制限より低く設定してください。推奨される方法は、-XX:MaxRAMPercentage を使用して、JVM がコンテナメモリの一定割合に基づいてヒープサイズを自動計算するようにすることです。
-XX:MaxRAMPercentage を使用したヒープサイズの設定(推奨)
デフォルトでは、JVM は OS からメモリ制限を読み取りますが、この値はホスト全体のメモリ量であり、コンテナの cgroup 制限ではありません。このため、JVM は過剰なヒープを割り当て、結果としてコンテナのメモリ制限を超えてしまいます。
-XX:+UseContainerSupport フラグを指定すると、JVM は OS の報告ではなく、cgroup からコンテナのメモリ制限およびプロセッサ数を読み取るようになります。これに加えて -XX:MaxRAMPercentage を併用することで、インスタンスの仕様変更時に手動での再構成なしで、ヒープサイズが自動的にスケールします。
以下の JVM オプションを使用します。
-XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof以下の表に、各オプションの説明を示します。
| オプション | 説明 |
|---|---|
-XX:+UseContainerSupport | ホスト OS への照会ではなく、cgroup からコンテナのメモリ制限およびプロセッサ数を読み取ります。-XX:InitialRAMPercentage および -XX:MaxRAMPercentage の正確な計算には、このフラグの指定が必須です。 |
-XX:InitialRAMPercentage | JVM ヒープに割り当てるコンテナメモリの初期割合を設定します。ガベージコレクション後にヒープサイズが変更されないようにするため、-XX:MaxRAMPercentage と同じ値を指定してください。推奨値は 70.0 です。 |
-XX:MaxRAMPercentage | JVM ヒープが使用できるコンテナメモリの最大割合を設定します。非ヒープメモリの確保を考慮し、70.0 以下を指定してください。上限は 75.0 を超えないようにしてください。 |
-XX:+PrintGCDetails | GC の詳細をログに出力します。 |
-XX:+PrintGCDateStamps | GC のタイムスタンプを出力します。例:2019-12-24T21:53:59.234+0800 |
-Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log | GC ログの出力先パスを指定します。コンテナディレクトリを NAS にマウントするか、Simple Log Service を使用して永続ストレージと自動ディレクトリ作成を有効化してください。 |
-XX:+HeapDumpOnOutOfMemoryError | JVM OOM エラー発生時に、自動的にヒープダンプファイルを生成します。 |
-XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof | ヒープダンプの出力先パスを指定します。永続ストレージと自動ディレクトリ作成を有効化するため、コンテナディレクトリを NAS にマウントしてください。 |
以下の互換性要件を確認してください。
-XX:+UseContainerSupport は、JDK 8u191 以降または JDK 10 以降を使用している場合にのみ有効です。ご使用の Java バージョンにおける OS 対応状況については、公式ドキュメントをご確認ください。JDK 11 以降では、-XX:+PrintGCDetails、-XX:+PrintGCDateStamps、および-Xloggc:$LOG_PATH/gc.logは非推奨です。-Xlog:gc:$LOG_PATH/gc.logを代わりに使用してください。
Dragonwell 11 では、${POD_IP} 変数はサポートされていません。/home/admin/nas が NAS にマウントされていない場合は、アプリケーション起動前に該当ディレクトリが存在することを確認してください。存在しない場合、ログは一切生成されません。-Xms および -Xmx を使用したヒープサイズの設定
コンテナのメモリ量に関係なく、固定のヒープサイズを必要とする場合に、-Xms および -Xmx を使用します。ただし、インスタンスの仕様を変更した後は、-Xmx の値を手動で更新する必要があります。
ヒープサイズがコンテナのメモリ制限に極めて近い場合、JVM ヒープが満杯になる前にコンテナが強制終了(終了コード 137)することがあります。この場合、ヒープダンプは生成されません。解決手順については、「コンテナが終了コード 137 で終了した場合の対応方法」をご参照ください。
以下の JVM オプションを使用します。
-Xms2048m -Xmx2048m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof| オプション | 説明 |
|---|---|
-Xms | 初期ヒープサイズを設定します。ガベージコレクションごとにヒープサイズが変更されないようにするため、-Xmx と同じ値を指定してください。 |
-Xmx | 最大ヒープサイズを設定します。コンテナ OOM を防ぐため、非ヒープコンポーネントに十分なメモリを確保してください。 |
以下の表に、一般的なコンテナメモリ構成に対する推奨ヒープサイズを示します。各値は、非ヒープ用途に約 30 % のコンテナメモリを確保しています。
| コンテナメモリ | 推奨ヒープサイズ |
|---|---|
| 1 GB | 600 MB |
| 2 GB | 1434 MB |
| 4 GB | 2867 MB |
| 8 GB | 5734 MB |
GC ログおよびヒープダンプに関するオプションについては、「-XX:MaxRAMPercentage を使用したヒープサイズの設定(推奨)」の表をご参照ください。これらのオプションおよび要件は同一です。
JDK 11 以降では、-XX:+PrintGCDetails、-XX:+PrintGCDateStamps、および-Xloggc:$LOG_PATH/gc.logは非推奨です。-Xlog:gc:$LOG_PATH/gc.logを代わりに使用してください。Dragonwell 11 では、${POD_IP}変数はサポートされていません。/home/admin/nasが NAS にマウントされていない場合は、アプリケーション起動前に該当ディレクトリが存在することを確認してください。
ヒープダンプファイルのダウンロード
JVM OOM エラーが発生すると、ヒープダンプは /home/admin/nas に書き込まれます。これをローカルで解析するには、以下の手順を実行します。
NAS ストレージの構成 を行い、コンテナ内の
/home/admin/nasディレクトリを NAS ディレクトリにマウントします。JVM オプションを構成し、ヒープダンプを
/home/admin/nasに書き込むようにします。-Xms2048m -Xmx2048m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprofOOM エラー発生後、ossutil を使用して、
.hprofファイルを/home/admin/nasからオンプレミス環境のマシンにダウンロードし、ローカルで解析します。手順については、「アプリケーションの健全性状態を確認するためのログのアップロードおよびダウンロード」をご参照ください。
よくある質問
コンテナが終了コード 137 で終了した場合の対応方法
終了コード 137 は、OOM Killer によってコンテナが強制終了されたことを意味します。これは、コンテナ全体のメモリ使用量(ヒープ+すべての非ヒープコンポーネント)がコンテナのメモリ制限を超えていることを示します。JVM ヒープ制限には到達していないため、ヒープダンプは生成されません。
非ヒープメモリの確保領域を増やすため、JVM ヒープサイズを小さくしてください。-XX:MaxRAMPercentage を使用している場合は、その値を下げてメモリ使用量を監視します。-Xmx を使用している場合は、「-Xms および -Xmx を使用したヒープサイズの設定」の推奨ヒープサイズを参照してください。

OOM エラーが発生しているが、ヒープダンプが生成されていません。原因は何ですか?
これは、JVM の独自の OOM ハンドラが起動する前に OOM Killer がコンテナを終了させた場合に発生します。JVM はヒープダンプを書き出す機会を得られません。
Java アプリケーションの場合、コンテナのメモリ制限に達する前に JVM OOM ハンドラが実行されるよう、JVM ヒープサイズを小さくしてください。Java 以外のアプリケーションの場合、インスタンスの仕様を変更 して、アプリケーションに十分なメモリを割り当ててください。
ヒープサイズをコンテナメモリ制限と同一の値に設定できますか?
いいえ。ヒープ外コンポーネント — メタスペース、スレッドスタック、GC オーバーヘッド、ダイレクトメモリ、およびSimple Log Service ログコレクターなどのシステムプロセス — はすべてヒープ外のメモリを消費します。ヒープサイズをコンテナメモリ制限と等しく設定すると、これらのコンポーネントにメモリが割り当てられず、コンテナ OOM が発生します。
JDK 8 で XX:MaxRAMPercentage を整数値で設定するとエラーが発生します。どうすればよいですか?
これは JDK 8 の既知のバグ(バグ ID 8219312)です。たとえば、JDK 8u191 で XX:MaxRAMPercentage=70 を設定すると、JVM は起動時に失敗します。
以下の 2 つの対応策があります。
小数値を使用する:
-XX:MaxRAMPercentage=70.0を70の代わりに指定します。-XX:InitialRAMPercentageおよび-XX:MinRAMPercentageについても同様で、JDK 8 ではいずれも整数値を受け付けません。JDK のアップグレード: JDK 10 以降へアップグレードしてください。

ヒープを 6 GB に設定した直後のメモリ使用量が低いのはなぜですか?
-Xms6g -Xmx6g を設定すると、6 GB の仮想アドレス空間が予約されますが、OS はアプリケーションが実際にそのメモリを使用するまで物理メモリを割り当てません。そのため、メモリ使用量は初期状態では低く、アプリケーションがオブジェクトを割り当てていくにつれて徐々に増加します。これは正常な動作です。
次のステップ
| トピック | 説明 |
|---|---|
| JVM オプション | SAE における JVM オプションの完全なリファレンス(ガベージコレクタの構成例を含む)。 |
| 起動コマンドの構成 | SAE アプリケーション向けのカスタム起動コマンドおよびパラメーターの構成方法。 |