加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

ArrayList容量增长中Java 6和Java 7之间的差异

发布时间:2020-12-15 08:26:16 所属栏目:Java 来源:网络整理
导读:我有一个问题,关于如何在 Java中管理ArrayList的容量增长(不是大小,而是容量). 当我们使用默认构造函数初始化ArrayList而不设置容量时,默认情况下容量设置为10. 此时,当我们向列表中添加另一个元素时,Oracle文档说“当元素添加到ArrayList时,其容量会自动增
我有一个问题,关于如何在 Java中管理ArrayList的容量增长(不是大小,而是容量).
当我们使用默认构造函数初始化ArrayList而不设置容量时,默认情况下容量设置为10.

此时,当我们向列表中添加另一个元素时,Oracle文档说“当元素添加到ArrayList时,其容量会自动增长.除了添加元素具有常量这一事实之外,未指定增长策略的详细信息摊销时间成本.“

如果我们看看Java内部,容量增长政策已经改变了它的功能.直到Java 6它是:

(1) int newCapacity = (oldCapacity * 3)/2 + 1;

从Java 7(和> 7)开始,它是:

(2) int newCapacity = oldCapacity + (oldCapacity >> 1);

但这两个数学系列略有不同.从默认值(10)开始,我们有:

(1)10,16,25,38,58,88,133,200,301,452 ……

(2)10,15,22,33,49,73,109,163,244,366 ……

我认为这对ArrayList的使用没有任何影响,但为什么他们改变了这个功能呢?有任何表现原因吗?他们发现了旧的瑕疵还是虫子?

解决方法

OpenJDK的 source control history显示它在 changeset 2350更改为 Martin Buchholz from Google以修复错误 JDK-6933217: Huge arrays handled poorly in core libraries.

新代码小心避免不必要的整数溢出.即使oldCapacity * 3/2没有,oldCapacity * 3也会溢出.新行oldCapacity(oldCapacity>> 1)不会.如果它确实溢出并且变为负数,则需要额外的代码来将容量设置为Integer.MAX_VALUE(或接近它).

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

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;
}

bug report的详细信息:

I’ve noticed bugs in java.util.ArrayList,java.util.Hashtable and
java.io.ByteArrayOutputStream which arise when the capacities of the
data structures reach a particular threshold. More below.

When the capacity of an ArrayList reaches (2/3)*Integer.MAX_VALUE its
size reaches its capacity and an add or an insert operation is
invoked,the capacity is increased by only one element. Notice that
in the following excerpt from ArrayList.ensureCapacity the new
capacity is set to (3/2) * oldCapacity + 1 unless this value would not
suffice to accommodate the required capacity in which case it is set
to the required capacity. If the current capacity is at least
(2/3)*Integer.MAX_VALUE,then (oldCapacity * 3)/2 + 1 overflows and
resolves to a negative number resulting in the new capacity being set
to the required capacity. The major consequence of this is that each
subsequent add/insert operation results in a full resize of the
ArrayList causing performance to degrade significantly.

06001

It is interesting to note that any statements about the amortized time
complexity of add/insert operations,such as the one in the ArrayList
javadoc,are invalidated by the performance related bugs. One
solution to the above situations is to set the new capacity of the
backing array to Integer.MAX_VALUE when the initial size calculation results in a negative number during a resize.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读