前言
今天在做题目的时候,无意中发现ArrayList(JDK 1.8)中定义了一个最大数组长度的常量:
/**
* 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;
这给我整懵逼了。。。于是有了下面的事情。。
数组对象长度极限
要说这个,必须得从对象的内存结构开始。
下面的大小以32bit操作系统为例
- 对象头Header
- MarkWord - 4Byte
记录对象运行时数据,例如:hashCode,分代年龄,锁信息等等 - 类型指针 - 4Byte
- 数组对象长度 - 4Byte
这个是数组对象独有
- 实例数据
- 对其填充
可以看到对于数组对象而言,需要在Header中用4个字节的长度保存数组长度,以此确定数组对象的大小。
所以,理论上,最大的数组长度,应该是Integer.MAX_VALUE。对的,就是理论上!因为不同的虚拟机实现上有差异。有些虚拟机会占用这4个字节的中的bits来存储一些信息。而HotSpot虚拟机所允许的最大数组长度是Integer.MAX_VALUE - 2.
如果有同学想要自己验证一把,可以先用-Xmx3g以上的堆空间大小,然后创建数组 byte[] art = new byte[Integer.MAX_VALUE - 2]
如果出现OOM:java heap space,则证明堆空间还是太小了,加大堆空间。因为Integer. MAX_VALUE=2^32次幂,2g * 1byte =2GB.注意空间大小就行了。如果出现OOM:Requested array size exceed VM limit. 则说明数组长度超过了虚拟机允许的最大长度。
ArrayList中的数组长度极限
本文开篇就给各位贴了代码了。为啥HotSpot最大长度是Integer.MAX_VALUE - 2,但是Java的ArrayList却要定义为Integer.MAX_VALUE - 8?
细心的朋友应该从上面的解释以及源码中的注释找到答案:
Some VMs reserve some header words in an array.
一些虚拟机实现在数组对象中保留一些header位数。这同样也是上面说的同一个意思。从中也可以看到,最多保留3bit。这也是Java源码严谨之处,屏蔽掉底层VM的实现差异。
最后
在JDK13开始,数组长度的极限定义,已不在ArrayList中,而是在ArraysSupport中。
总算搞清楚了,不枉我花费一下午(其实秘密一直都在源码注释中写的明明白白!)。。