清空一个 ArrayList 还是只创建一个新的 ArrayList,让旧的数组被垃圾回收?
清空一个集合(在我的例子中是一个ArrayList)与创建一个新集合(并让垃圾回收器清除旧集合)的优点和缺点是什么?
具体来说,我有一个叫.当发生某种情况时,我需要清空并用其他内容重新填充它。我应该打电话还是只是做一个新的,让旧的垃圾收集?每种方法的优缺点是什么?ArrayList<Rectangle>
list
list
list.clear()
ArrayList<Rectangle>
清空一个集合(在我的例子中是一个ArrayList)与创建一个新集合(并让垃圾回收器清除旧集合)的优点和缺点是什么?
具体来说,我有一个叫.当发生某种情况时,我需要清空并用其他内容重新填充它。我应该打电话还是只是做一个新的,让旧的垃圾收集?每种方法的优缺点是什么?ArrayList<Rectangle>
list
list
list.clear()
ArrayList<Rectangle>
回收一个(例如通过调用)的好处是,您可以避免分配新一个的开销,以及增加它的成本......如果你没有提供一个很好的提示。ArrayList
clear
initialCapacity
回收的缺点包括:ArrayList
该方法必须分配给 s 后备数组中的每个(使用的)插槽。clear()
null
ArrayList
不会调整支持阵列的大小以释放内存。因此,如果您反复填充并清除列表,它最终将(永久)使用足够的内存来表示它遇到的最大列表。换句话说,您增加了内存占用量。你可以通过调用 来解决这个问题,但这会创建一个垃圾对象,依此类推 1。clear()
trimToSize()
存在可能影响性能的地方性和跨代问题。当您反复回收 时,对象及其后备数组可能会被永久保留。这意味着:ArrayList
列表对象和表示列表元素的对象可能位于堆的不同区域,这可能会增加 TLB 未命中和页面流量,尤其是在 GC 时间。
将(年轻一代)引用分配到(终身)列表的支持数组中可能会产生写入障碍开销...取决于 GC 实现。
无法为实际应用准确模拟性能权衡。变量太多了。然而,“公认的智慧”是,如果你有足够的内存2和一个半体面的垃圾收集器,回收通常不是一个好主意。
同样值得注意的是,现代JVM可以非常有效地分配对象。它只需要更新到堆的“free”指针并写入2或3个对象标头字。内存归零由GC完成...除了这样做的工作之外,这大致相当于在正在回收的列表中消除引用所做的工作。clear()
1 - 对于性能而言,创建新的 ArrayList 比调用 clear() 后跟 trimToSize(...) 更好。使用后者,您既可以获得垃圾回收开销,也可以获得多余的空值开销。
2 - 如果垃圾对象与非垃圾对象的比例较高,则复制收集器的效率更高。如果您分析这种收集器的工作方式,则几乎所有成本都用于查找和复制可访问的对象。对垃圾对象唯一需要做的就是阻止零写入已抽真空的“从”空间,以便为分配新对象做好准备。
我的建议是不要回收对象,除非你有明显的需要最小化(垃圾)对象创建率;例如,因为它是减少(有害)GC暂停的唯一选择。ArrayList
在所有条件相同的情况下,在现代热点JVM上,我的理解是,通过执行以下操作,您将获得最佳性能:
initialSize
当您想要减少 GC 上的负载时,可以保留容器并进行调用:将数组内的所有引用归零,但不使数组符合垃圾回收器回收的条件。这可能会加快将来的插入速度,因为内部的数组不需要增长。当您计划添加到容器中的数据与清除时大致相同的大小时,此方法尤其有利。clear
clear()
ArrayList
此外,当其他对象保存对要清除的数组的引用时,您可能需要使用。clear
当新数据的大小可能与以前不同时,释放容器并创建新容器是有意义的。当然,您可以通过与 组合调用来实现类似的效果。clear()
trimToSize()