使用ArrayList#trimToSize()方法?

时间:2014-01-31 11:10:30

标签: java collections arraylist

a recently posted question我遇到了ArrayList#trimToSize(),它将支持数组的大小减少到当前的集合大小。

引用javadoc

  

将此ArrayList实例的容量调整为列表的当前容量   尺寸。应用程序可以使用此操作来最小化存储   一个ArrayList实例。

Javadoc说应用程序可以用来减少后备阵列的内存占用。如果我没有错,这种方法对于小尺寸不会有用,因为一些参考的成本不会那么大。

但是由于1.7中的arraylist int newCapacity = (oldCapacity * 3)/2 + 1;和1.7中的int newCapacity = oldCapacity + (oldCapacity >> 1);使用的算法,如果oldcapacity很大则添加新元素,那么它将使用上述算法创建一个新的后备数组如果在动态扩展后只添加一个元素,则可以分配很多不需要的空间。

我的方法背后的方法是正确的,还是有其他一些应用程序?

3 个答案:

答案 0 :(得分:8)

是的,支持阵列在满员时增加了约50%。例如,下面的程序增加了100万个条目,调用trimToSize然后添加一个条目。添加条目后,背衬阵列的长度为1.2米,修剪后1米,添加一个项目后1.5米。

因此,除非您知道不再添加到列表中,否则调用trimToSize可能会适得其反。

ArrayList<Integer> list = new ArrayList<>();
Field e = list.getClass().getDeclaredField("elementData");
e.setAccessible(true);
for (int i = 0; i < 1_000_000; i++) {
    list.add(i);
}
System.out.println(((Object[]) e.get(list)).length); //1215487
list.trimToSize();
System.out.println(((Object[]) e.get(list)).length); //1000000
list.add(0);
System.out.println(((Object[]) e.get(list)).length); //1500000

答案 1 :(得分:1)

另一种情况是我们添加元素然后删除其中的许多元素。当我们删除元素时,内部aray保持不变。

答案 2 :(得分:1)

您的公式导致最差情况下的开销只有50%的空插槽。请注意,Object最小大小为24个字节,而阵列中的压缩OOP仅为4个字节。开销相当于

(0.5*4) / (24+4) == 1/14 == 7%

几乎不值得考虑 - 这是最差的。平均而言,它是数组条目中开销的一半,并且通常对象要大得多。

所以唯一一次调用trimToSize是有意义的是在从一个以前巨大的arraylist大量删除之后。换句话说,几乎从来没有。