Java OutOfMemoryError Requested Array Size Exceeds VM Limit - Java 147

Java OutOfMemoryError Requested Array Size Exceeds VM Limit – Java 147

建立 Array 時,超過 VM 陣列大小上限,JVM 會在分配的資料結構上,會執行一項檢查,確定是否可以 Addressable 尋址,可分配大小為 2,147,483,645,及 Integer.MAX_VALUE-2 的陣列,若增加一點點長度,如: Integer.MAX_VALUE-1 就會拋出此錯誤,本篇增加了範例,並透過單元測試來驗證產出結果。

Java 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 。

發佈留言