7. 要求されたアレイ サイズが VM 制限を超えています

7.1 要求されたアレイ サイズが VM 制限を超えています 概要

Java には、アプリケーションが割り当てることができる最大配列サイズに制限があり、正確な制限はプラットフォームによって異なりますが、通常は 10 ~ 21 億要素の間になります。

これに直面した場合java.lang.OutOfMemoryError: Requested array size exceeds VM limit、それは、JVM がサポートできるより大きな配列を割り当てようとしたためにアプリケーションがクラッシュしたことを意味します。

7.2 理由

このエラーは、JVM のネイティブ コードによってスローされます。配列にメモリを割り当てる前に発生し、JVM は、割り当てられるデータ構造がこのプラットフォームでアドレス指定可能かどうかというプラットフォーム依存のチェックを実行します。間違いはそれほど一般的ではありません。あなたが最初に思うかもしれないように。

このエラーがほとんど発生しない理由は、Java 配列が int 型でインデックス付けされているためです。Java の最大の正の整数は 2^31 -1 = 2,147,483,647 です。プラットフォームに依存する制限は、たとえば MacBook Pro ではこの数値にかなり近くなります。 、Java 1.7 では、配列を 2,147,483,645 またはInteger.MAX_VALUE-2要素。

配列の長さに 1 を追加すると、Integer.MAX_VALUE-1この OutOfMemoryError が発生します。

Exception in thread “main” java.lang.OutOfMemoryError:
Requested array size exceeds VM limit

ただし、この制限がそれほど高くない場合もあります。32 ビット Linux、OpenJDK 6 では、約 11 億要素の配列を割り当てるときにエラーが発生します。特定の環境の制限サイズを知るには、次の小さなコマンドを実行できますjava.lang.OutOfMemoryError: Requested array size exceeds VM limit。テストプログラム。

7.3 例

エラーを再現してみるためにjava.lang.OutOfMemoryError: Requested array size exceeds VM limit、次のコードを見てみましょう。

for (int i=3; i>=0; i--) {
    try {
        int[] arr = new int[Integer.MAX_VALUE-i];
        System.out.format("Successfully initialized an array with %,d elements .\n", Integer.MAX_VALUE-i);
    } catch (Throwable t) {
        t.printStackTrace();
    }
}

この例では 4 回ループし、各ループでプリミティブの長い配列を初期化します。プログラムが初期化しようとしている配列のサイズは、反復ごとに 1 ずつ増加し、最終的には integer に達しますMAX_VALUE64 ビット Mac OS X で Hotspot 7 を使用してスニペットを起動すると、次のような出力が得られるはずです。

java.lang.OutOfMemoryError: Java heap space
  at eu.plumbr.demo.ArraySize.main(ArraySize.java:8)
java.lang.OutOfMemoryError: Java heap space
  at eu.plumbr.demo.ArraySize.main(ArraySize.java:8)
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
  at eu.plumbr.demo.ArraySize.main(ArraySize.java:8)
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
  at eu.plumbr.demo.ArraySize.main(ArraySize.java:8)

最後の 2 回の試行が行われる前にjava.lang.OutOfMemoryError: Requested array size exceeds VM limit、割り当て失敗により、より一般的なjava.lang.OutOfMemoryError: Java heap spaceメッセージが報告されることに注意してください。これは、割り当てようとしている 2^31-1 int には 8G メモリが必要であり、これは JVM のデフォルト メモリよりもはるかに大きいためです。

この例は、このエラーがいかにまれであるかを示しています。VM が配列サイズの制限に達していることを確認するには、プラットフォームの制限と、要件を満たす 2 つの配列の長さの間のデータを割り当てる必要がInteger.MAX_INTありInteger.MAX_INT-1ますInteger.MAX_INT

7.4 解決策

java.lang.OutOfMemoryError: Requested array size exceeds VM limit次の 2 つの状況で発生します。

  • 配列が大きすぎて、最終的なサイズがプラットフォームの制限Integer.MAX_INTと範囲の間にあります。
  • 具体的には、その制限を実験するために 2^31-1 要素より大きい配列を割り当てようとしています。

最初のケースでは、コードベースをチェックして、そのような大きな配列が本当に必要かどうかを確認してください。おそらく、配列のサイズを小さくしてそれで済むかもしれません。または、配列をより小さな散布点に分割し、プラットフォームの制限内で必要なデータをバッチにロードします。

2 番目のケースでは、Java 配列は int によってインデックス付けされることに注意してください。そのため、プラットフォームで標準のデータ構造を使用する場合、要素の配列は 2^31-1 を超えることはできません。実際、この場合、コンパイラはコンパイル中に「エラー: 整数が大きすぎます」と通知したときにすでに停止しています。

ただし、非常に大規模なデータセットを扱う場合は、オプションを再検討する必要があります。必要なデータを小さいバッチでロードしながら、標準の Java ツールを使用することもできます。そうでない場合は、ユーティリティを使用しなくなる可能性があります。これを実現する 1 つの方法は、次のとおりです。sun.misc.Unsafe授業。これにより、C と同様にメモリを直接割り当てることができます。

おすすめ

転載: blog.csdn.net/east4ming/article/details/80179704