和我一起迎接明天的太阳吧

klaus08

焦虑源于行动的匮乏

ArrayList最大容量

先看源代码


    /**
     * 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。(不过我觉得最后这几个空间没什么必要了,只有极少数情况才会用到并且不发生OOM吧)

在自己电脑上试了一下,OOM

posted @ 2021-10-04 16:54  klaus08  阅读(503)  评论(0编辑  收藏  举报