JVM中数组长度限制
发现问题
当写下这行代码时,程序会注定运行失败。
String strs[] = new String[Integer.MAX_VALUE];
错误信息:java.lang.OutOfMemoryError: Requested array size exceeds VM limit.
而且在jdk源码中总会看到类似这样的定义:
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
分析问题
看注释可以了解到,jvm会为数组头信息保留一些空间。官方给出的解释。我们去看看jvm内部是如何实现的。
objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) {
//...
if (length > arrayOopDesc::max_array_length(T_ARRAY)) {
// 在这抛出异常
report_java_out_of_memory("Requested array size exceeds VM limit");
JvmtiExport::post_array_size_exhausted();
THROW_OOP_0(Universe::out_of_memory_error_array_size());
}
//...
}
其中, T_ARRAY = 13,表示数据类型。
enum BasicType {
T_BOOLEAN = 4,
T_CHAR = 5,
T_FLOAT = 6,
T_DOUBLE = 7,
T_BYTE = 8,
T_SHORT = 9,
T_INT = 10,
T_LONG = 11,
T_OBJECT = 12,
T_ARRAY = 13,
T_VOID = 14,
T_ADDRESS = 15,
T_NARROWOOP = 16,
T_METADATA = 17,
T_NARROWKLASS = 18,
T_CONFLICT = 19, // for stack value type with conflicting contents
T_ILLEGAL = 99
};
根据数据类型,获得对象头大小
// Return the maximum length of an array of BasicType. The length can passed
// to typeArrayOop::object_size(scale, length, header_size) without causing an
// overflow. We also need to make sure that this will not overflow a size_t on
// 32 bit platforms when we convert it to a byte size.
static int32_t max_array_length(BasicType type) {
// 判断数据类型是否正确
assert(type >= 0 && type < T_CONFLICT, "wrong type");
assert(type2aelembytes(type) != 0, "wrong type");
const size_t max_element_words_per_size_t =
align_down((SIZE_MAX/HeapWordSize - header_size(type)), MinObjAlignment);
const size_t max_elements_per_size_t =
HeapWordSize * max_element_words_per_size_t / type2aelembytes(type);
if ((size_t)max_jint < max_elements_per_size_t) {
// It should be ok to return max_jint here, but parts of the code
// (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
// passing around the size (in words) of an object. So, we need to avoid
// overflowing an int when we add the header. See CRs 4718400 and 7110613.
return align_down(max_jint - header_size(type), MinObjAlignment);
}
return (int32_t)max_elements_per_size_t;
}
至此我们了解到,jvm中,数组对象的头上是有一些信息的,这些信息需要占用一定的空间,所以在java中,新建数组是不可以指定其大小为Integer.MAX_VALUE。而且在内存中分配这么大的对象,在编码中也是不提倡的。
Go deeper!