原创

Why the maximum array size of ArrayList is Integer.MAX_VALUE - 8

最近在研究 jdk 1.8源码(JDKSource1.8),看到ArrayList 部分, 发现一个很奇怪的地方:

jdk 1.8 ArrayList line 191

/**
   * 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;

官方注释的意思是:该值的设置用于表示数组的最大容量,由于一些虚拟机在数组中会保留一些头字。尝试分配较大的数组可能会导致内存不足错误, 也就是我们常说的内存溢出(VM内存限制)。

但是, 理解 Some VMs reserve some header words in an array. 这句话还是很费解的.

我们知道,Integer.MAX_VALUE 为 2^31, 即Integer.MAX_VALUE - 8 为 2^31 - 8 = 2,147,483,648 - 8 = 2,147,483,640。那接下来我们就聊聊,为什么是减8?

原因:

  • 1、存储 Headerwords(并不是在所有虚拟机中都这样,只是部分虚拟机在数组中保留了一些头信息),因此该现象仅为部分存在;
  • 2、避免内存溢出,减少出错几率
  • 3、最大值其实还是为 Integer.MAX_VALUE,并不是Integer.MAX_VALUE-8。(因为只是为了规避不同平台机器内存溢出的风险)
    • 见内部私有静态方法 private static int hugeCapacity(int minCapacity)
      private void grow(int minCapacity) {
      // overflow-conscious code
      int oldCapacity = elementData.length;
      int newCapacity = oldCapacity + (oldCapacity >> 1);
      if (newCapac
      ity - 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;
      }
      

int newCapacity = oldCapacity + (oldCapacity >> 1);
这句执行后如果超过int的最大值那么newCapacity会是一个负数,这个需要了解一下数字二进制的加减原理。

下面这四句就是针对newCapacity溢出变成负数的时候的处理:

    if (newCapacity - minCapacity < 0) {
      newCapacity = minCapacity;
    }
    if (newCapacity - MAX_ARRAY_SIZE > 0) {
      newCapacity = hugeCapacity(minCapacity);
    }

Headerwords, 即对象头信息

包括两部分信息:Mark Word(标记字段)和 Klass Pointer(类型指针)。
该存储其实只会在部分虚拟机中才被使用。

一句话总结

同一技术问题理解各有差异。 此文仅个人理解,如果存在问题, 欢迎纠正。


Integer.MAX_VALUE-8 其实并不是ArrayList的真实的最大长度,最大长度仍为Integer.MAX_VALUE
只不过 -8 的真正意义是为了减少不同平台因差异化实现的出错的几率


正文到此结束
广告是为了更好的提供数据服务
本文目录