Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaのOutOfMemoryError(OOM)とは?発生原理と根本原因を特定する3つの手順


OutOfMemoryErrorとは

OutOfMemoryErrorは、JVMが新しいオブジェクトにメモリを割り当てるための十分な空きメモリを持っていないときに、JVMによってスローされるエラーです。Javaの例外クラス階層において、これはExceptionではなくErrorカテゴリに分類されます。Errorはアプリケーション側での回復が困難な重大な問題を表すものだからです。

OutOfMemoryErrorを意図的に発生させる方法

  • 大きなサイズのメモリを連続して確保し、ヒープメモリ領域を使い果たします。
  • メモリの割り当てを繰り返すと、やがてJVMが割り当て可能なメモリを使い切った時点でOutOfMemoryErrorがスローされます。
  • エラーをキャッチしたら、後から統計情報を作成できるように内容をログに記録しておきます。

サンプルコード

public class OutOfMemoryErrorDemo {
    public static void main(String[] args) throws Exception {
        int dummyArraySize = 15;
        System.out.println("Max JVM memory: " + Runtime.getRuntime().maxMemory());
        long memoryConsumed = 0;
        try {
            long[] memoryAllocated = null;
            for(int loop = 0; loop < Integer.MAX_VALUE; loop++) {
                memoryAllocated = new long[dummyArraySize];
                memoryAllocated[0] = 0;
                memoryConsumed += dummyArraySize * Long.SIZE;
                System.out.println("Memory Consumed till now: " + memoryConsumed);
                dummyArraySize *= dummyArraySize * 2;
                Thread.sleep(500);
            }
        } catch (OutOfMemoryError outofMemory) {
            System.out.println("Catching out of memory error");
            // 統計情報を生成できるよう、情報をログに記録する
            throw outofMemory;
        }
    }
}

実行結果

Max JVM memory: 119537664
Memory Consumed till now: 960
Memory Consumed till now: 29760
Memory Consumed till now: 25949760
Catching out of memory error
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at OutOfMemoryErrorDemo.main(OutOfMemoryErrorDemo.java:9)

OOMの根本原因を特定する手順

ステップ1:OutOfMemoryError発生時にヒープダンプを取得する

アプリケーションを起動するときに、VM引数として-XX:+HeapDumpOnOutOfMemoryErrorを指定します。この設定により、OOMが発生した時点でJVMが自動的にヒープダンプを出力するようになります。

$ java -XX:+HeapDumpOnOutOfMemoryError ...

ステップ2:問題を再現する

開発環境で問題を再現できない場合は、本番環境で再現させる必要があるかもしれません。問題を再現してアプリケーションがOOMをスローすると、そのタイミングでヒープダンプファイルが生成されます。

ステップ3:ヒープダンプファイルを使って調査する

VisualVMを使ってヒープダンプファイルを読み込み、問題を診断します。VisualVMは従来JDK_HOME/bin/jvisualvmとしてJDKに同梱されていましたが、JDK 9以降は別途ダウンロードが必要になっています。ヒープダンプファイルには、アプリケーションのメモリ使用状況に関する詳細な情報がすべて含まれているため、どのオブジェクトがメモリを占有しているのかを特定できます。より高度な分析を行いたい場合は、Eclipse Memory Analyzer(MAT)などの専用ツールを利用するのも有効です。

  1. JavaのJTextFieldとJTextAreaの違いとは?特徴と使い分けを解説

    JavaのGUIアプリケーションにおけるJTextFieldとJTextAreaの最大の違いは、JTextFieldが1行のテキスト入力に対応しているのに対し、JTextAreaは複数行のテキスト入力に対応しているという点です。どちらもSwingが提供するテキストコンポーネントであり、共通の親クラスであるJTextComponentを継承しています。 JTextFieldとは JTextFieldは、ユーザーが1行形式でテキストを入力できる、最も基本的かつ重要なコンポーネントの一つです。 テキストフィールド内で入力操作を行うと、ActionListenerインターフェースによるイベントが発生

  2. JavaのJFrameとJDialogの違いとは?特徴と使い分けを解説

    JavaのSwingには、ウィンドウを表示するためのトップレベルコンテナとしてJFrameとJDialogが用意されています。どちらもよく似た役割を持ちますが、動作や用途には重要な違いがあります。この記事では、それぞれの特徴をサンプルコードとともに解説し、最後に使い分けのポイントをまとめます。 JFrameとは フレームに追加されたコンポーネントは「コンテンツ」として扱われ、contentPaneによって管理されます。JFrameにコンポーネントを追加する際は、フレーム本体ではなくcontentPaneに対して追加する必要があります。 JFrameは、タイトル、境界線、(オプションで)メニュ