最大intサイズの配列を作成できないのはなぜですか?
int i = 2147483647;
int[] array = new int[i];
私はこの説明を見つけました:
Java配列は32ビットintを介してアクセスされるため、理論上の最大配列サイズは2147483647要素になります。
しかし、ご覧のとおり、私のコードは機能しません。サイズのある配列を作成することもできません
new int[Integer.MAX_VALUE - 5];
[〜#〜] ps [〜#〜]
なぜ -5
実際に?
考えられる例外は2つあります。
OutOfMemoryError: Java heap space
は、配列がJavaヒープスペースに収まらないことを意味します。解決するには、JVMオプション-Xmx
を使用して最大ヒープサイズを増やすことができます。また、考慮してください。その オブジェクトの最大サイズは最大ヒープ生成より大きくすることはできません 。OutOfMemoryError: Requested array size exceeds VM limit
は、プラットフォーム固有のサイズを超えたことを意味します:2^31-1=2147483647
要素によって制限されます。HotSpotのJVM配列サイズは、内部表現によって制限されます。 GCコードでは、JVMはヒープワードの配列のサイズをint
として渡し、ヒープワードからjint
に変換し直すと、オーバーフローが発生する可能性があります。したがって、クラッシュや予期しない動作を回避するために、最大配列長は (max size --header size) によって制限されます。 ヘッダーサイズ は、実行しているJVMのビルドに使用されたC/C++コンパイラ(Linuxの場合はgcc、macosの場合はclang)、およびランタイム設定(UseCompressedClassPointers
など)によって異なります。たとえば私のLinuxでは:
Integer.MAX_VALUE
Integer.MAX_VALUE-1
Integer.MAX_VALUE-2
一部のVMは、配列内のいくつかのヘッダーワードを予約します。
「安全な」最大数はbe 2 147 483 639 (Integer.MAX_VALUE - 8)
です。
ソース-http://www.docjar.com/html/api/Java/util/ArrayList.Java.html
**
191 * The maximum size of array to allocate.
192 * Some VMs reserve some header words in an array.
193 * Attempts to allocate larger arrays may result in
194 * OutOfMemoryError: Requested array size exceeds VM limit
195 */
196 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
したがって、システム上のJVMで使用可能な最大メモリに依存します。
編集:なぜそれがOOMを表示しているのか。
要素数= 2 147 483 639
1つの要素に必要なバイト数= 4
要素だけの合計メモリ8589934556 KB == 8.589934555999999 GB
配列の合計メモリ使用量が8バイトの倍数でない場合、サイズは次の8の倍数に切り上げられます。
したがって、オーバーヘッドのために割り当てているものよりも多くのものが必要であり、それは継続的なメモリである必要があります
その割り当てに十分なヒープを用意するだけでは十分ではありません。十分なサイズの単一のヒープregionが必要です。ご存知のように、ヒープは世代に分けられます。
8 GBの単一の割り当ての場合、単一のヒープ領域(およびある程度のオーバーヘッド)に対してその量を確保する必要があります。 12GBの-Xmx
あなたはまだ不足しているかもしれません。追加のオプションを使用して、旧世代のサイズを制御します。
さて、Ivanは、配列の長さには明確に定義された上限があり、JVM /プラットフォームに依存していることをすでに正しく指摘しています。実際、さらに重要なことに、コードで実際に作成できる配列の長さは、主に実行中にプログラムに割り当てた最大ヒープスペースの量によって制御されると彼は述べました。
彼の説明をサポートするために、小さなコードスニペットを追加したいと思います。たとえば、理論的には、配列[]は長さ<= INTEGER.MAX_VALUE-x(ここで、xはJVM /プラットフォーム固有のヘッダーサイズ)を受け入れる必要がありますが、実行するとします以下 JavaプログラムとVMオプション-Xmx32mの場合、作成された配列はいずれもMAX_ARRAY_SIZEに近い長さに達していないことがわかります(つまり、2147483639)。
byte []配列:1バイト
0 l = 1048576 s = 1mb
1 l = 2097152 s = 2mb
2 l = 4194304 s = 4mb
3 l = 8388608 s = 8mb
Java.lang.OutOfMemoryError:Javaヒープスペースl = 16777216 s = 16mb
char []配列:2バイト
0 l = 1048576 s = 2mb
1 l = 2097152 s = 4mb
2 l = 4194304 s = 8mb
Java.lang.OutOfMemoryError:Javaヒープスペースl = 8388608 s = 16mb
int []配列:4バイト
0 l = 1048576 s = 4mb
1 l = 2097152 s = 8mb
Java.lang.OutOfMemoryError:Javaヒープスペースl = 4194304 s = 16mb
double []配列:8バイト
0 l = 1048576 s = 8mb
Java.lang.OutOfMemoryError:Javaヒープスペースl = 2097152 s = 16mb
以下のコードは次のとおりです:
byte[] barray = null;
System.out.println("\nbyte[] array : 1 byte");
try {
for (ii=0; ii < 32; ii++) {
barray = new byte[(int)Math.pow(2, ii)*1024*1024];
System.out.println(ii + " l=" + barray.length + " s=" + barray.length / (1024 * 1024) + "mb");
}
}
catch (Throwable e) {
barray = null;
System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + (int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb");
}
char[] carray = null;
System.out.println("\nchar[] array : 2 byte");
try {
for (ii=0; ii < 32; ii++) {
carray = new char[(int)Math.pow(2, ii)*1024*1024];
System.out.println(ii + " l=" + carray.length + " s=" + 2*carray.length / (1024 * 1024) + "mb");
}
}
catch (Throwable e) {
carray = null;
System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + 2*(int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb");
}
int[] iarray = null;
System.out.println("\nint[] array : 4 byte");
try {
for (ii=0; ii < 32; ii++) {
iarray = new int[(int)Math.pow(2, ii)*1024*1024];
System.out.println(ii + " l=" + iarray.length + " s=" + 4*iarray.length / (1024 * 1024) + "mb");
}
}
catch (Throwable e) {
iarray = null;
System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + 4*(int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb");
}
double[] darray = null;
System.out.println("\ndouble[] array : 8 byte");
try {
for (ii=0; ii < 32; ii++) {
darray = new double[(int)Math.pow(2, ii)*1024*1024];
System.out.println(ii + " l=" + darray.length + " s=" + 8*darray.length / (1024 * 1024) + "mb");
}
}
catch (Throwable e) {
darray = null;
System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + 8*(int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb");
}
cmdに移動してこの行を入力し、最大ヒープサイズを見つけます
javaw -XX:+PrintFlagsFinal | find "MaxHeapSize"
次に、それを1.5
で割ると、コンピューターの配列のおおよその最大サイズが得られます。