ホームページ  >  記事  >  Java  >  Java 例外 OutOfMemoryError の解決策

Java 例外 OutOfMemoryError の解決策

不言
不言転載
2019-01-30 11:08:173116ブラウズ

この記事の内容は Java 例外 OutOfMemoryError の解決方法です。必要な方は参考にしていただければ幸いです。

Java 仮想マシン仕様の説明では、プログラム カウンターに加えて、仮想マシン メモリの他のいくつかの実行領域でも OOM 例外が発生する可能性があります。ここでは、コードを使用して各ランタイム領域に何が保存されているかを確認し、それを処理する方法について説明します。

Java ヒープ オーバーフロー

オブジェクトが継続的に作成され、GC ルートとの間に到達可能なパスがある限り、Java ヒープはオブジェクト インスタンスを格納するために使用されます。ガベージ コレクション メカニズムを回避してこれらのオブジェクトをクリアすると、オブジェクト数が最大ヒープ容量制限に達した後にメモリ オーバーフロー例外が発生します。

例外の再現

コードでは次の仮想マシン パラメータを使用します:

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

このようにして、Java ヒープのサイズは次のように制限されます。 20MB で拡張できません。パラメータ -XX: HeapDumpOnOutOfMemoryError を使用すると、メモリ オーバーフロー例外が発生したときに、仮想マシンが分析のために現在のメモリ ヒープ ダンプ スナップショットをダンプできるようになります。

次のコードを使用して検証します:

public class HeapOOM {
    static class OOMObject {
    }
    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();

        while (true) {
            list.add(new OOMObject());
        }
    }
}

実行結果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid3460.hprof ...
Heap dump file created [28199779 bytes in 0.237 secs]

解決策

Java ヒープ メモリの OOM 例外は、実際には共通メモリです。アプリケーション オーバーフロー例外が発生すると、多くの場合、「Java ヒープ スペース」というプロンプトが表示されます。

この領域の異常を解決するには、まずMATなどのメモリイメージ解析ツールを使用して、メモリリークやメモリオーバーフローが発生していないかを確認するのが一般的な方法です。

メモリ リークの場合は、さらにツールを使用してリークしたオブジェクトから GC ルートへの参照チェーンを表示し、リークしたオブジェクトが GC ルートとどのように関連付けられているか、ガベージ コレクターによる自動的なリサイクルの防止を確認できます。彼らの空間。

メモリ リークではない場合、つまり、メモリ内のオブジェクトが本当に存続する必要がある場合は、仮想マシンのヒープ パラメータを確認し、それをマシンの物理メモリと比較する必要があります。増やすことができるかどうかを確認してください。コードの観点から、一部のオブジェクトのライフサイクルが長すぎたり、状態の保持時間が長すぎたりする状況がないかどうかを確認し、プログラムの実行中のメモリ消費量を減らすようにしてください。

仮想マシン スタックとローカル メソッド スタックのオーバーフロー

HotSpot 仮想マシンでは仮想マシン スタックとローカル メソッド スタックが区別されないため、HotSpot では -Xoss パラメータが存在しますが、実際、スタック容量は -Xss パラメータによってのみ設定されます。

例外の再現

シングル スレッドでは、コードは次の仮想マシン パラメータを使用します。

-Xss128k

このパラメータを使用してスタック容量を削減し、次のコードを使用して再現します。例外:

public class JavaVMStackSOF {

    private int stackLength = 1;

    public void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) throws Throwable {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }
}

Solution

仮想マシンのデフォルトのパラメータを使用する場合、スタックの深さはほとんどの場合異なります (各メソッドによってスタックにプッシュされるフレーム サイズが異なるため)同じではないので、ほとんどの場合、1000 ~ 2000 に達しても問題ないとしか言​​えません。通常のメソッド呼び出し (再帰を含む) では、この深さで完全に十分です。

ただし、スレッドの作成が多すぎるためにメモリ オーバーフローが発生し、スレッド数を減らすことができないか、64 ビットの仮想マシンを置き換えることができない場合は、最大ヒープを減らすしか方法がありません。配線の増加と引き換えにスタック容量も増加します。

ネイティブ ダイレクト メモリ オーバーフロー

DirectMemory 容量は -XX: MaxDirectMemorySize で指定できます。指定しない場合、デフォルトはJava の最大ヒープ。

例外の再現

次の仮想マシン パラメータを使用します:

-Xmx20M -XX:MaxDirectMemorySize=10M

次のコードを使用して例外を再現します:

public class DirectMemoryOOM {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);//直接申请分配内存
        }
    }
}

解決策

By DirectMemory によって引き起こされるメモリ オーバーフローの明らかな特徴は、ヒープ ダンプ ファイルに明らかな例外が見られないことです。

OOM 後のダンプ ファイルが非常に小さく、NIO がプログラム内で直接的または間接的に使用されていることが判明した場合は、それが理由かどうかを確認することを検討できます。

以上がJava 例外 OutOfMemoryError の解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
前の記事:J2EEとは次の記事:J2EEとは