OutOfMemoryErrorをスローするのに十分なメモリがない場合はどうなりますか?


207

すべてのオブジェクトがヒープメモリを必要とし、スタック上のすべてのプリミティブ/リファレンスがスタックメモリを必要とすることを知っています。

ヒープ上にオブジェクトを作成しようとしたときにメモリ不足が発生すると、JVMはヒープ上にjava.lang.OutOfMemoryErrorを作成し、それをスローします。

つまり、暗黙的に、これは起動時にJVMによって予約されたメモリがあることを意味します。

この予約メモリが使い果たされるとどうなるでしょう(間違いなく使い果たされます。以下の説明をお読みください)。java.lang.OutOfMemoryErrorのインスタンスを作成するのに十分なメモリがJVMにヒープにない場合はどうなりますか?

ぶら下がっているだけですか?または、OOMのインスタンスにnullメモリがないため、彼は私を投げますnewか?

try {
    Object o = new Object();
    // and operations which require memory (well.. that's like everything)
} catch (java.lang.OutOfMemoryError e) {
    // JVM had insufficient memory to create an instance of java.lang.OutOfMemoryError to throw to us
    // what next? hangs here, stuck forever?
    // or would the machine decide to throw us a "null" ? (since it doesn't have memory to throw us anything more useful than a null)
    e.printStackTrace(); // e.printStackTrace() requires memory too.. =X
}

==

JVMが十分なメモリを予約できないのはなぜですか?

予約されているメモリの量に関係なく、JVMにそのメモリを「再利用」する方法がない場合は、そのメモリが使い果たされる可能性があります。

try {
    Object o = new Object();
} catch (java.lang.OutOfMemoryError e) {
    // JVM had 100 units of "spare memory". 1 is used to create this OOM.
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        // JVM had 99 units of "spare memory". 1 is used to create this OOM.
        try {
            e.printStackTrace();
        } catch (java.lang.OutOfMemoryError e3) {
            // JVM had 98 units of "spare memory". 1 is used to create this OOM.
            try {
                e.printStackTrace();
            } catch (java.lang.OutOfMemoryError e4) {
                // JVM had 97 units of "spare memory". 1 is used to create this OOM.
                try {
                    e.printStackTrace();
                } catch (java.lang.OutOfMemoryError e5) {
                    // JVM had 96 units of "spare memory". 1 is used to create this OOM.
                    try {
                        e.printStackTrace();
                    } catch (java.lang.OutOfMemoryError e6) {
                        // JVM had 95 units of "spare memory". 1 is used to create this OOM.
                        e.printStackTrace();
                        //........the JVM can't have infinite reserved memory, he's going to run out in the end
                    }
                }
            }
        }
    }
}

またはもっと簡潔に:

private void OnOOM(java.lang.OutOfMemoryError e) {
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        OnOOM(e2);
    }
}

2
あなたの答えは、JVMに大きく依存しています
MozenRath

23
私がかつて(90年代に)使用した1つのテレフォニーライブラリは、をキャッチしてOutOfMemoryExceptionから、大きなバッファーの作成を伴う何かを行うために使用しました...
Tom Hawtin-タックライン

@ TomHawtin-tacklineそれを行うことに関連する操作が別のOOMをスローするとどうなるでしょうか。
ペーチェリエ

38
携帯電話のように、バッテリーが切れますが、「バッテリー切れです」とスパムを続けるのに十分なバッテリーがあります。
カズマ

1
「この予約メモリが使い果たされるとどうなるか」:プログラムが最初のメモリをキャッチし、OutOfMemoryErrorそれへの参照を保持している場合にのみ発生する可能性があります。OutOfMemoryErrorあなたがそれをキャッチすることであなたのプログラムの状態についてほとんど何も保証することができないので、それをキャッチすることは人が考えるほど有用ではないことを思い出させます。stackoverflow.com/questions/8728866/…を
Raedwald

回答:


145

JVMが実際にメモリ不足になることはありません。事前にヒープスタックのメモリ計算を行います。

JVM構造、第3章、セクション3.5.2は次のように述べています。

  • Java仮想マシンスタックを動的に拡張でき、拡張が試行されたが、メモリ不足のために拡張を実行できない場合、またはメモリ不足のために新しいスレッドの初期Java仮想マシンスタックを作成できない場合、Java仮想マシンがスローしOutOfMemoryErrorます。

以下のためにヒープ、セクション3.5.3。

  • 自動ストレージ管理システムで利用できるよりも多くのヒープが計算に必要な場合、Java仮想マシンはをスローしOutOfMemoryErrorます。

そのため、オブジェクトの割り当てを行う前に、事前に計算を行います。


何が起こるかは、JVMが永続生成領域(PermSpace)と呼ばれるメモリ内のオブジェクトにメモリを割り当てようとすることです。割り当てが失敗した場合(JVMがガベージコレクターを呼び出して空き領域を試行して割り当てた後でも)、がスローされますOutOfMemoryError。例外でもメモリスペースが必要なので、エラーは無期限にスローされます。

参考文献。?さらに、OutOfMemoryError異なるJVM構造で発生する可能性があります


10
はい、ということですが、Java仮想マシンもOutOfMemoryErrorをスローするためにメモリを必要としませんか?OOMをスローするためのメモリがない場合はどうなりますか?
パセリエ

5
しかし、JVMがOOMの同じインスタンスへの参照を返さない場合、予約されたメモリが最終的に不足することに同意しませんか?(質問のコードに示されているように)
12

1
私はここでグラハムさんのコメントへの参照を置くことを許可する:stackoverflow.com/questions/9261705/...
Pacerier

2
VMが、述べられている極端なケース、および原子力発電所でOOM例外のシングルトンを保持している場合は、良いかもしれません。
ジョンK

8
@JohnK:スペースシャトルやボーイング757がJavaでプログラミングされていないのと同じように、原子力発電所がJavaでプログラミングされていないことを望みます。
ディートリッヒエップ

64

グラハム・ボーランドは正しいようです:少なくとも私の JVMは明らかにOutOfMemoryErrorsを再利用しています。これをテストするために、簡単なテストプログラムを作成しました。

class OOMTest {
    private static void test (OutOfMemoryError o) {
        try {
            for (int n = 1; true; n += n) {
                int[] foo = new int[n];
            }
        } catch (OutOfMemoryError e) {
            if (e == o)
                System.out.println("Got the same OutOfMemoryError twice: " + e);
            else test(e);
        }
    }
    public static void main (String[] args) {
        test(null);
    }
}

これを実行すると、次の出力が生成されます。

$ javac OOMTest.java && java -Xmx10m OOMTest 
Got the same OutOfMemoryError twice: java.lang.OutOfMemoryError: Java heap space

ところで、私が(Ubuntu 10.04で)実行しているJVMはこれです:

$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

編集:次のプログラムを使用して、JVMにメモリを完全に実行させた場合にどうなるかを確認しようとしました。

class OOMTest2 {
    private static void test (int n) {
        int[] foo;
        try {
            foo = new int[n];
            test(n * 2);
        }
        catch (OutOfMemoryError e) {
            test((n+1) / 2);
        }
    }
    public static void main (String[] args) {
        test(1);
    }
}

結局のところ、それは永遠にループするようです。ただし、奇妙なことに、プログラムをCtrl+で終了しようとしてもC機能せず、次のメッセージしか表示されません。

Java HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated


バージョン「1.7.0_01」は、Java HotSpot(TM)64ビットサーバーVMと私のための同じニースのテスト、
Pacerier

面白い。JVMが末尾再帰を完全に理解していないように見えます...(まるで末尾再帰スタックの再利用を行っているかのようですが、すべてのメモリをクリーンアップするには十分ではありません...)
Izkata

コードを変更して、どれだけ多くの異なるものが得られるかを確認しました-elseブランチは常に正確に5回実行されます。
Irfy

@Izkata:nOOMを常にスローできるように、OOM を事前に割り当て、後でそのうちの1つを再利用することは意識的な決定だと思います。Sun / OracleのJVMは、IIRCでテール再帰をサポートしていませんか?
Irfy

10
@Izkataメモリーが不足した後、JVMが常に同じ(5番目程度)OOMをスローしているため、ループは明らかに無限に実行されています。そのためn、スタック上にフレームがありn+1、永遠にフレームを作成および破棄することになり、無限に実行されているように見えます。
Irfy

41

ほとんどのランタイム環境は、起動時に事前に割り当てるか、そうでなければメモリ不足の状況に対処するのに十分なメモリを予約します。ほとんどの健全なJVM実装がこれを行うと思います。


1
stackoverflow.com/questions/9261215/…:Trueですが、JVMがそれを行うために100ユニットのメモリを予約し、最初のOOMに1ユニットを費やした場合、私のOOMキャッチブロックでe.printStackTrace()を実行するとどうなりますか?e.printStackTrace()にもメモリが必要です。次に、JVMは別のメモリを使用して別のOOM(残り98ユニット)をスローし、e.printStackTrace()でそれをキャッチするので、JVMは別のOOM(残り97ユニット)をスローし、キャッチされて欲しかった..
12

3
これが、OOMEがスタックトレースを含めるために使用したことがない理由です。OOMEは、Java 6(blogs.oracle.com/alanb/entry/…)にスタックトレースを含めようと試み始めただけです。スタックトレースが不可能な場合は、スタックトレースなしで例外がスローされると思います。
Sean Reilly、

1
@SeanReillyつまり、スタックトレースを持たない例外は依然としてオブジェクトであり、依然としてメモリが必要です。スタックトレースが提供されているかどうかにかかわらず、メモリが必要です。OOMを作成するためのメモリが残っていない場合(スタックトレースなしでメモリを作成するためのメモリがない場合)、catchブロックでnullをキャッチするのは本当ですか?
ペーチェリエ

17
JVMは、OOM例外の単一の静的インスタンスへの複数の参照を返す可能性があります。したがって、catch句がより多くのメモリを使用しようとしても、JVMは同じOOMインスタンスを何度も何度もスローし続けることができます。
グラハムボーランド

1
@TheEliteGentlemanそれらも非常に良い答えだと私は同意しますが、JVMは物理マシン上にあります。これらの答えは、JVMがOOMのインスタンスを常に提供するのに十分なメモリを魔法のように持つ方法を説明していません。「それは常に同じインスタンスです」は謎を解決するようです。
パセリエ

23

前回Javaで作業していてデバッガを使用していたとき、ヒープインスペクタは、JVMが起動時にOutOfMemoryErrorのインスタンスを割り当てたことを示しました。言い換えれば、プログラムがメモリを使い果たして、ましてメモリ不足になる前に、オブジェクトを割り当てます。


12

JVM仕様の第3.5.2章から:

Java仮想マシンスタックを動的に拡張でき、拡張が試行されたが、メモリ不足のために拡張を実行できない場合、またはメモリ不足のために新しいスレッド用の初期Java仮想マシンスタックを作成できない場合、Java仮想マシンがスローしOutOfMemoryErrorます。

すべてのJava仮想マシンは、それがスローされることを保証する必要がありOutOfMemoryErrorます。つまり、OutOfMemoryErrorヒープ領域が残っていなくても、インスタンスを作成できる(または事前に作成しておく必要がある)必要があります。

保証する必要はありませんが、それをキャッチして素敵なスタックトレースを出力するのに十分なメモリがあることを...

添加

複数のコードをスローする必要がある場合、JVMがヒープ領域を使い果たす可能性があることを示すコードを追加しましたOutOfMemoryError。しかし、そのような実装は上からの要件に違反します。

スローされたのインスタンスOutOfMemoryErrorが一意である、またはオンデマンドで作成されるという要件はありません。JVMはOutOfMemoryError起動時にのインスタンスを1つだけ準備し、ヒープ領域が不足するたびにこれをスローできます。これは、通常の環境では1回です。つまり、表示されるインスタンスはOutOfMemoryErrorシングルトンである可能性があります。


これを実装するには、スペースが狭い場合はスタックトレースを記録しないようにする必要があります。
Raedwald

@Raedwald:実際のところ、これはOracle VMの機能です。私の答えをご覧ください。
sleske 2012年

11

興味深い質問:-)。他の人たちは理論的な側面について良い説明をしてくれましたが、私はそれを試すことにしました。これは、Oracle JDK 1.6.0_26、Windows 7 64ビット上にあります。

テスト設定

メモリを使い果たす簡単なプログラムを作成しました(以下を参照)。

プログラムは単にstaticを作成し、java.util.ListOOMがスローされるまで新しい文字列をそこに詰め続けます。次に、それをキャッチし、無限ループ(不十分なJVM ...)でスタッフィングを続けます。

テスト結果

出力からわかるように、OOMEがスローされる最初の4回には、スタックトレースが付属しています。その後、後続のOOMEはjava.lang.OutOfMemoryError: Java heap spaceprintStackTrace()が呼び出された場合にのみ印刷されます。

したがって、JVMはスタックトレースを出力できる場合はそれを出力しようとするようですが、メモリが非常に少ない場合は、他の回答が示唆するように、トレースを省略します。

また、OOMEのハッシュコードも興味深いものです。最初のいくつかのOOMEはすべて異なるハッシュを持っていることに注意してください。JVMがスタックトレースの省略を開始すると、ハッシュは常に同じになります。これは、JVMが可能な限り新しい(事前割り当て済み?)OOMEインスタンスを使用することを示唆していますが、プッシュが発生した場合、何もスローせずに同じインスタンスを再利用します。

出力

注:出力を読みやすくするために、一部のスタックトレースを切り詰めました( "[...]")。

iteration 0
iteration 100000
iteration 200000
iteration 300000
iteration 400000
iteration 500000
iteration 600000
iteration 700000
iteration 800000
iteration 900000
iteration 1000000
iteration 1100000
iteration 1200000
iteration 1300000
iteration 1400000
iteration 1500000
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1069480624
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.ArrayList.ensureCapacity(Unknown Source)
    at java.util.ArrayList.add(Unknown Source)
    at testsl.Div.gobbleUpMemory(Div.java:23)
    at testsl.Div.exhaustMemory(Div.java:12)
    at testsl.Div.main(Div.java:7)
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 616699029
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 2136955031
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1535562945
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
[...]

プログラム

public class Div{
    static java.util.List<String> list = new java.util.ArrayList<String>();

    public static void main(String[] args) {
        exhaustMemory();
    }

    private static void exhaustMemory() {
        try {
            gobbleUpMemory();
        } catch (OutOfMemoryError e) {
            System.out.println("Ouch: " + e+"; hash: "+e.hashCode());
            e.printStackTrace();
            System.out.println("Keep on trying...");
            exhaustMemory();
        }
    }

    private static void gobbleUpMemory() {
        for (int i = 0; i < 10000000; i++) {
            list.add(new String("some random long string; use constructor to force new instance"));
            if (i % 10000000== 0) {
                System.out.println("iteration "+i);
            }
        }

    }
}

pushがshoveになると、OOMEにメモリを割り当てることができないため、すでに作成されているメモリをフラッシュします。
ブハケシンディ

1
軽微な注意:出力の一部は順序が正しくないようです。おそらく、出力先System.outがデフォルトでprintStackTrace()使用System.errしているためです。どちらかのストリームを一貫して使用すると、おそらくより良い結果が得られます。
Ilmari Karonen

@IlmariKaronen:はい、気づきました。これは単なる例であるため、問題ではありませんでした。明らかに、本番用コードでは使用しません。
sleske

確かに、最初に出力を調べたときに****が何をしていたのかを理解するのに少し時間がかかりました。
Ilmari Karonen、2012


4

マネージメモリ環境の境界に違反する試みを示す例外は、その環境のランタイム(この場合はJVM)によって処理されます。JVMは独自のプロセスであり、アプリケーションのILを実行しています。プログラムが呼び出しスタックを制限を超えて呼び出す呼び出しを試みたり、JVMが予約できるよりも多くのメモリを割り当てようとしたりすると、ランタイム自体が例外を挿入し、呼び出しスタックが巻き戻されます。プログラムが現在必要とするメモリの量、またはそのコールスタックの深さに関係なく、JVMは独自のプロセス境界内に十分なメモリを割り当て、前述の例外を作成してコードに挿入します。


「JVMは独自のプロセス境界内に十分なメモリを割り当てて、上記の例外を作成します」しかし、コードがその例外への参照を保持しているため再利用できない場合、別の方法で作成するにはどうすればよいですか?それとも、特別なシングルトンOOMEオブジェクトがあることを示唆していますか?
Raedwald

私はそれを示唆していません。プログラムが、JVMまたはOSによって作成および挿入されたものを含め、これまでに作成されたすべての例外をトラップしてハングする場合、最終的にJVM自体がOSによって設定された境界を超え、OSはGPFまたは同様のエラー。ただし、そもそもそれは悪いデザインです。例外は処理してからスコープ外にするか、スローする必要があります。また、SOEやOOMEを捕まえて続行しようとしないでください。「クリーンアップ」以外の方法で正常に終了できるため、これらの状況で実行を継続するために実行できることはありません。
KeithS

「そもそも悪いデザイン」:ひどいデザイン。しかし、はっきりと言えば、JVMがその方法で失敗した場合、JVMは仕様に準拠していますか?
Raedwald

4

JVMがJavaプログラムを実行するJVMによって予約されている仮想メモリを、JVMがネイティブプロセスとして実行されるホストOSのネイティブメモリと混同しているようです。マシン上のJVMは、Javaプログラムを実行するためにJVMが予約したメモリではなく、OSが管理するメモリで実行されています。

参考文献:

そして最後に、java.lang.Errorキャッチしようとしています。あなたに任意の有用な情報を与えないかもしれませんスタックトレースを印刷するために(とその子孫クラス)。代わりにヒープダンプが必要です。


4

@Graham Borlandの答えをさらに明確にするために、JVMは起動時にこれを行います。

private static final OutOfMemoryError OOME = new OutOfMemoryError();

その後、JVMは「new」、「anewarray」、または「multianewarray」のいずれかのJavaバイトコードを実行します。この命令により、JVMはメモリ不足の状態でいくつかのステップを実行します。

  1. たとえば、ネイティブ関数を呼び出しますallocate()allocate()特定のクラスまたは配列の新しいインスタンスにメモリを割り当てようとします。
  2. その割り当て要求は失敗するため、JVMはdoGC()ガベージコレクションを実行しようとする別のネイティブ関数(など)を呼び出します。
  3. その関数が戻るallocate()と、インスタンスにメモリをもう一度割り当てようとします。
  4. それが失敗した場合(*)、JVMはallocate()内throw OOME;で、起動時にインスタンス化されたOOMEを参照してを実行します。そのOOMEを割り当てる必要はなく、参照するだけであることに注意してください。

明らかに、これらは文字通りのステップではありません。実装はJVMによって異なりますが、これは大まかな考え方です。

(*)失敗する前にかなりの量の作業がここで行われます。JVMは、SoftReferenceオブジェクトをクリアしようとし、世代別コレクターを使用する場合は、古い世代への直接割り当てを試みます。


3

JVMが事前に割り当てるという回答OutOfMemoryErrorsは確かに正しいです。
メモリ不足の状況を引き起こしてこれをテストすることに加えて、任意のJVMのヒープを確認するだけです(Java 8アップデート31からOracleのHotspot JVMを使用して実行する、スリープを実行する小さなプログラムを使用しました)。

使用jmapすると、OutOfMemoryErrorのインスタンスが9つあるように見えます(十分なメモリがある場合でも)。

> jmap -histo 12103 | grep OutOfMemoryError
 71:9 288 java.lang.OutOfMemoryError
170:1 32 [Ljava.lang.OutOfMemoryError;

次に、ヒープダンプを生成できます。

> jmap -dump:format = b、file = heap.hprof 12315

そして、Eclipse Memory Analyzerを使用してそれを開きます。OQLクエリは、JVMが実際OutOfMemoryErrorsにすべての可能なメッセージに事前に割り当てているように見えることを示しています。

ここに画像の説明を入力してください

これらを実際に事前に割り当てるJava 8 Hotspot JVMのコードはここにあり、次のようになっています(一部は省略しています)。

...
// Setup preallocated OutOfMemoryError errors
k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false);
k_h = instanceKlassHandle(THREAD, k);
Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_gc_overhead_limit =
  k_h->allocate_instance(CHECK_false);

...

if (!DumpSharedSpaces) {
  // These are the only Java fields that are currently set during shared space dumping.
  // We prefer to not handle this generally, so we always reinitialize these detail messages.
  Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg());

  msg = java_lang_String::create_from_str("Metaspace", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg());
  msg = java_lang_String::create_from_str("Compressed class space", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg());

  msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg());

  msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg());

  msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
  java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());

  // Setup the array of errors that have preallocated backtrace
  k = Universe::_out_of_memory_error_java_heap->klass();
  assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error");
  k_h = instanceKlassHandle(THREAD, k);

  int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0;
  Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(k_h(), len, CHECK_false);
  for (int i=0; i<len; i++) {
    oop err = k_h->allocate_instance(CHECK_false);
    Handle err_h = Handle(THREAD, err);
    java_lang_Throwable::allocate_backtrace(err_h, CHECK_false);
    Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h());
  }
  Universe::_preallocated_out_of_memory_error_avail_count = (jint)len;
}
...

また、このコードは、JVMが最初に、スタックトレース用のスペースを使用して事前に割り当てられたエラーの1つを使用しようとし、その後スタックトレースなしのエラーにフォールバックすることを示しています。

oop Universe::gen_out_of_memory_error(oop default_err) {
  // generate an out of memory error:
  // - if there is a preallocated error with backtrace available then return it wth
  //   a filled in stack trace.
  // - if there are no preallocated errors with backtrace available then return
  //   an error without backtrace.
  int next;
  if (_preallocated_out_of_memory_error_avail_count > 0) {
    next = (int)Atomic::add(-1, &_preallocated_out_of_memory_error_avail_count);
    assert(next < (int)PreallocatedOutOfMemoryErrorCount, "avail count is corrupt");
  } else {
    next = -1;
  }
  if (next < 0) {
    // all preallocated errors have been used.
    // return default
    return default_err;
  } else {
    // get the error object at the slot and set set it to NULL so that the
    // array isn't keeping it alive anymore.
    oop exc = preallocated_out_of_memory_errors()->obj_at(next);
    assert(exc != NULL, "slot has been used already");
    preallocated_out_of_memory_errors()->obj_at_put(next, NULL);

    // use the message from the default error
    oop msg = java_lang_Throwable::message(default_err);
    assert(msg != NULL, "no message");
    java_lang_Throwable::set_message(exc, msg);

    // populate the stack trace and return it.
    java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(exc);
    return exc;
  }
}

良い投稿です。これを1週間の回答として受け入れ、前の回答に戻る前に可視性を高めます。
Pacerier

Java 8以降では、Permanent Generation Spaceが完全に削除され、Java 8以降ではと呼ばれる動的クラスメタデータメモリ管理が導入されているため、ヒープ領域割り当てメモリサイズを指定できなくなりましたMetaspace。PermGenにも対応できるコードの一部を表示して、それをメタスペースと比較することもできます。
ブハケシンディ2015

@BuhakeSindi-パーマネントジェネレーションがこれとどう関係しているのかわかりません。新しいオブジェクトは、回答で述べているように、Permanent Generationに割り当てられません。また、OutOfMemoryErrorsが事前に割り当てられているという事実については決して触れません(これが質問に対する実際の答えです)。
Johan Kaving、2015年

1
わかりました、私が言っていることは、Java 8からオブジェクトの割り当てが動的に計算されるのに対し、事前に定義されたヒープ領域に割り当てられる前に、おそらく事前に割り当てられているということです。OOMEは事前に割り当てられていますが、OOMEをスローする必要があるかどうかを判断するために「計算」が行われます(そのため、なぜJLS仕様を参照したのですか)。
ブハケシンディ2015

1
Javaヒープサイズは、以前と同じようにJava 8で事前定義されています。Permanent Generationは、クラスメタデータ、インターンされた文字列、クラススタティックを含むヒープの一部でした。ヒープサイズの合計とは別に調整する必要のあるサイズに制限がありました。Java 8では、クラスメタデータがネイティブメモリに移動し、インターン文字列とクラススタティックが通常のJavaヒープに移動しました(たとえば、こちら:infoq.com/articles/Java-PERMGEN-Removedを参照)。
Johan Kaving、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.