如何在ArrayLists中定义容量的概念?

时间:2011-03-23 20:17:44

标签: java arraylist capacity

我理解容量是ArrayList中可能包含或不包含引用对象的值的元素或可用空间的数量。我试图更多地了解容量的概念。

所以我有三个问题:

1)从内存的角度来定义容量代表的哪些好方法是什么?

...分配给ArrayList的(连续?)内存?

...... ArrayLists在(堆?)上的内存占用?

2)如果上述情况属实,那么改变容量需要某种方式的内存管理开销?

3)任何人都有一个例子,其中#2是或可能是一个性能问题?可能还有大量的大型ArrayLists不断调整其容量?

4 个答案:

答案 0 :(得分:3)

  1. 该类称为ArrayList,因为它基于数组。容量是数组的大小,需要一块连续的堆内存。但请注意,数组本身仅包含元素的引用,这些元素是堆上的单独对象。
  2. 增加容量需要分配一个新的更大的数组,并将旧数组中的所有引用复制到新数组,之后旧数组才有资格进行垃圾回收。
  3. 您已经引用了可能令人担忧的主要案例。在实践中,我从未见过它实际上成为一个问题,因为元素对象通常比列表占用更多的内存(可能还有CPU时间)。

答案 1 :(得分:2)

ArrayList的实现方式如下:

class ArrayList {
  private Object[] elements;
}

容量是该数组的大小。

现在,如果您的容量为10,并且您要添加第11个元素,则ArrayList将执行此操作:

Object[] newElements = new Object[capacity * 1.5];
System.arraycopy(this.elements, newElements);
this.elements = newElements;

因此,如果你从一个小容量开始,ArrayList将最终创建一堆数组并在你不断添加元素时为你复制东西,这是不好的。

另一方面,如果您指定容量1,000,000并且只向ArrayList添加3个元素,那也有点不好。

经验法则:如果您知道容量,请指定它。如果您不确定但知道上限,请指定。如果您不确定,请使用默认值。

答案 2 :(得分:1)

容量就像你描述的那样 - 分配给ArrayList以存储值的连续内存。 ArrayList将所有值存储在数组中,并自动为您调整数组大小。这在调整大小时会导致内存管理开销。

如果我没记错的话,当你尝试添加一个元素而不是容量时,Java会将ArrayList的后备阵列的大小从大小N增加到大小为2N + 2。我不知道当您使用insert方法(或类似方法)插入超出容量结束的特定位置时,或者是否允许这样做时,它会增加到什么大小。

这是一个帮助您思考其工作原理的示例。将| s之间的每个空格描绘为后备阵列中的单元格:

| | |

size = 0(不包含元素),capacity = 2(可包含2个元素)。

|1| |

size = 1(包含1个元素),capacity = 2(可包含2个元素)。

|1|2|

size = 2,capacity = 2.添加另一个元素:

|1|2|3| | | |

尺寸增加1,容量增加到6(2 * 2 + 2)。对于大型数组而言,这可能是昂贵的,因为分配大的连续内存区域可能需要一些工作(而不是分配许多小块内存的LinkedList),因为JVM需要搜索适当的位置,并且可能需要要求操作系统获得更多内存。将大量值从一个地方复制到另一个地方也很昂贵,一旦找到这样的地区就会这样做。

我的经验法则是:如果您知道所需的容量,请使用ArrayList,因为只有一个分配,访问速度非常快。如果您不知道所需的容量,请使用LinkedList,因为添加新值总是需要相同的工作量,并且不涉及复制。

答案 3 :(得分:0)

  

1)从内存角度定义容量代表的哪些好方法是什么?

     

...分配给ArrayList的(连续?)内存?

是的,ArrayList由数组备份,表示内部数组大小。

  

... ArrayLists在(堆?)上的内存占用?

是的,阵列容量越大,arraylist使用的占用空间越多。

  

2)如果上述情况属实,那么更改容量需要某种方式的内存管理开销?

是的。当列表变得足够大时,将分配更大的数组并复制内容。之前的数组可能会被丢弃并标记为垃圾回收。

  

3)任何人都有一个例子,其中#2是或可能是性能问题?可能还有大量的大型ArrayLists不断调整其容量?

是的,如果您创建初始容量为1的ArrayList(例如),并且您的列表会超出该列表。如果您事先知道要存储的元素数量,则最好请求该大小的初始容量。

然而我认为这应该在您的优先级列表中较低,而阵列复制可能经常发生,它从Java的早期阶段开始优化,并且不应该成为一个问题。我认为最好是选择正确的算法。请记住:Premature optimization is the root of all evil

另请参阅:When to use LinkedList over ArrayList