java数组最大长度_java的数组最大可以容纳多少个元素

如题图,库函数里的数组最大数量都是指定为Integer.MAX_VALUE-8。按注释所说,8是为对象头预留的,对象头在64位虚拟机下占16个字节,8一定不是指字节数,如果指的是字长,那么这个数字应该是可以更小的。

找到分配数组的代码

typeArrayOop TypeArrayKlass::allocate_common(int length, bool do_zero, TRAPS) {

assert(log2_element_size() >= 0, "bad scale");

if (length >= 0) {

if (length <= max_length()) { //看这里 size_t size = typeArrayOopDesc::object_size(layout_helper(), length);

KlassHandle h_k(THREAD, this);

typeArrayOop t;

CollectedHeap* ch = Universe::heap();

if (do_zero) {

t = (typeArrayOop)CollectedHeap::array_allocate(h_k, (int)size, length, CHECK_NULL);

} else {

t = (typeArrayOop)CollectedHeap::array_allocate_nozero(h_k, (int)size, length, CHECK_NULL);

}

return t;

} else {

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());

}

} else {

THROW_0(vmSymbols::java_lang_NegativeArraySizeException());

}

}

可以注意到 length 大于max_length()的时候就会抛出Requested array size exceeds VM limit异常,而这个max_length是在初始化的时候设置的:

TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name) {

set_layout_helper(array_layout_helper(type));

assert(is_array_klass(), "sanity");

assert(is_typeArray_klass(), "sanity");

set_max_length(arrayOopDesc::max_array_length(type)); //看这里 assert(size() >= TypeArrayKlass::header_size(), "bad size");

set_class_loader_data(ClassLoaderData::the_null_class_loader_data());

}

计算过程:

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_size_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_size_down(max_jint - header_size(type), MinObjAlignment);

}

return (int32_t)max_elements_per_size_t;

}

而这个SIZE_MAX是一个较为巨大的数字:

#define SIZE_MAX UINT64_MAX#define UINT64_MAX 18446744073709551615ULL

所以最后都会落到这里:

return align_size_down(max_jint - header_size(type), MinObjAlignment);

此时:MinObjAlignment值为1,align_size_down这个宏可以忽略。

header_size即为对象头所占的字长(对齐/不对齐):

static int header_size(BasicType type) {

size_t typesize_in_bytes = header_size_in_bytes();

return (int)(Universe::element_type_should_be_aligned(type)

? align_object_offset(typesize_in_bytes/HeapWordSize)

: typesize_in_bytes/HeapWordSize);

}

基础类型只有Double和Long需要对齐:

inline bool Universe::element_type_should_be_aligned(BasicType type) {

return type == T_DOUBLE || type == T_LONG;

}

对齐的函数:(可以简单理解为字长+1取偶数部分)

#define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))

所以数组最大的大小即为:Integer.MAX_VALUE-对象头占的字长。

以64位开启压缩指针为例:markword占8个字节,klass指针4个字节,数组长度4个字节,一共是16个字节(两个)字长。

public class Hello {

public static void main(String[] args) {

Object[] o = new Object[Integer.MAX_VALUE-2];

}

}

运行:java -Xmx9000m -Xmn10m Hello,不会有任何异常。

假如关掉压缩指针,klass指针占8个字节,对象头一共8+8+4,再加上补齐,一共是3个字长,那么此时最大数组大小就是Integer.MAX_VALUE-3了。

$ java -Xmx9000m -Xmn10m -XX:-UseCompressedOops Hello

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

at Hello.main(Hello.java:4)

32位虚拟机数组的对象头:markword占4个字节,klass指针占4个字节,数组长度占4个字节,一共是3个字长。在不需要对齐的情况下数组最大最小为Integer.MAX_VALUE-3,而在需要对齐的情况下就是Integer.MAX_VALUE-4。(这一个没有验证,因为我没有装32位的jdk...)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值