建立 Array 時,超過 VM 陣列大小上限,JVM 會在分配的資料結構上,會執行一項檢查,確定是否可以 Addressable 尋址,可分配大小為 2,147,483,645,及 Integer.MAX_VALUE-2 的陣列,若增加一點點長度,如: Integer.MAX_VALUE-1 就會拋出此錯誤,本篇增加了範例,並透過單元測試來驗證產出結果。
Table of Contents
ToggleJava OutOfMemoryError
Requested Array Size Exceeds VM Limit
超過 Array 長度大小上限,設定 JVM Arguments。
-Xmn3g -Xms12g -Xmx12g
檔案目錄
./
+- src
+- test
| +- org
| +- ruoxue
| +- java_147
| +- memory
| +- RequestedArraySizeExceedsVMLimitTest.java
測試 JUnit 4
intArray
建立一個超大的 int Array。
@Test
public void intArray() {
int[] array = new int[Integer.MAX_VALUE];
assertNotNull(array);
}
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
stringArray
建立一個超大的 String Array。
@Test
public void stringArray() {
String[] array = new String[Integer.MAX_VALUE];
assertNotNull(array);
}
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
byteArray
建立一個超大的 ByteByte Array。
@Test
public void byteArray() {
Byte[] array = new Byte[Integer.MAX_VALUE];
assertNotNull(array);
}
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Java Heap Space
沒有超過超過 Array 長度大小上限,不過很容易拋出此類錯誤。
@Test
public void normal() {
for (int i = 0; i < 4; i++) {
int[] array = new int[Integer.MAX_VALUE - 2];
assertNotNull(array);
}
}
[GC (Allocation Failure) 8390144K->8390144K(12580864K), 0.0083153 secs]
[Full GC (Allocation Failure) 8390144K->723K(12580864K), 0.1339523 secs]
RequestedArraySizeExceedsVMLimitTest.java
package org.ruoxue.java_147.memory;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
public class RequestedArraySizeExceedsVMLimitTest {
@Test
public void intArray() {
int[] array = new int[Integer.MAX_VALUE];
assertNotNull(array);
}
@Test
public void stringArray() {
String[] array = new String[Integer.MAX_VALUE];
assertNotNull(array);
}
@Test
public void byteArray() {
Byte[] array = new Byte[Integer.MAX_VALUE];
assertNotNull(array);
}
@Test
public void normal() {
for (int i = 0; i < 4; i++) {
int[] array = new int[Integer.MAX_VALUE - 2];
assertNotNull(array);
}
}
}
心得分享
在有些平台上,這個最大限制可能還會更小一些,例如在 32位 Linux, OpenJDK 6,陣列長度大約在11億左右 (約2^30) 就會拋出此錯誤,參考以下情況作進一步調整:
檢查業務邏輯,確認是否真的需要那麼大的陣列,如果可以降低陣列長度,就可以避免此情況,如果真的需要,可以考慮把資料拆分為多個區塊,然後資料批次加載。
陣列使用 int 當作索引。所以元素不能超過 2^31-1 個,實際上,程式碼在編譯階段就會報錯,提示訊息為 error: integer number too large 。