[英]Java: Compact a HashMap (analogue of ArrayList#trimToSize)
[英]Use of ArrayList#trimToSize() method?
从最近发布的一个问题中,我遇到了ArrayList#trimToSize() ,它将支持数组的大小减小到当前的集合大小。
引用javadoc
将此ArrayList实例的容量调整为列表的当前大小。 应用程序可以使用此操作来最小化ArrayList实例的存储。
Javadoc说应用程序可以用来减少后备阵列的内存占用。 如果我没有错,这种方法对于小尺寸不会有用,因为一些参考的成本不会那么大。
但是由于arraylist int newCapacity = (oldCapacity * 3)/2 + 1;
使用的算法int newCapacity = (oldCapacity * 3)/2 + 1;
在1.6和int newCapacity = oldCapacity + (oldCapacity >> 1);
在1.7中,当添加新元素时,如果oldcapacity
很大,那么它将使用上述算法创建一个新的后备数组,如果在动态扩展后只添加一个元素,则可以分配很多不需要的空间。
我的理由是正确的方法背后还是有其他一些应用程序?
是的,支持阵列在满员时增加了约50%。 例如,下面的程序增加了100万个条目,调用trimToSize
然后添加一个条目。 添加条目后,背衬阵列的长度为1.2米,修剪后1米,添加一个项目后1.5米。
因此,除非您知道不再添加到列表中, trimToSize
调用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
另一种情况是我们添加元素然后删除其中的许多元素。 当我们删除元素时,内部aray保持不变。
您的公式导致最差情况下的开销只有50%的空插槽。 请注意, Object
的最小大小为24个字节,而阵列中的压缩OOP仅为4个字节。 开销相当于
(0.5*4) / (24+4) == 1/14 == 7%
这几乎不值得考虑 - 这是它可以得到的最糟糕的 。 平均而言,它是数组条目中开销的一半,而且对象通常要大得多。
因此,调用trimToSize
之后唯一有意义的是在从之前庞大的arraylist中大量删除之后。 换句话说,几乎从不。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.