先看源代码
/**
* 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;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
在进行扩容时会调用grow(int minSize)
,参数是扩容所需的最小空间,如果该容量小于原容量的1.5倍,那么扩容后的容量就是原容量的1.5倍;否则扩容后容量等于所需求容量(要多少给多少,不多给,前提是不超过规定的最大值)。
但是最大值这里出现了问题:
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
既然已经超过了 MAX_ARRAY_SIZE,为什么不抛出异常,而是进入到 hugeCapacity,并且可以看到在 hugeCapacity方法中最大分配容量居然是 Integer.MAX_VALUE?比上面的 MAX_ARRAY_SIZE 还可以多 8 个字节。为什么要这样设计呢?
原因就是下面这段注释:
有些虚拟机,会保留数组的前八个字节做头部,为了照顾这些虚拟机尽量不发生OutOfMemoryError
的错误,所以设置了 MAX_ARRAY_SIZE的值。这个其实已经能满足大部分需求了,如果还是不可以的话就给最大空间Integer.MAX_VALUE。(不过我觉得最后这 8字节没什么必要了,只有极少数情况才会用到并且不发生OOM吧)
在自己电脑上试了一下,OOM