Java 清空ArrayList,还是创建一个新的ArrayList,然后让旧的ArrayList被垃圾收集?

Java 清空ArrayList,还是创建一个新的ArrayList,然后让旧的ArrayList被垃圾收集?,java,collections,arraylist,garbage-collection,Java,Collections,Arraylist,Garbage Collection,清空一个集合(在我的例子中是ArrayList)与创建一个新集合(并让垃圾收集器清除旧集合)相比,有哪些优点和缺点 具体来说,我有一个名为list的ArrayList。当某种情况发生时,我需要清空列表,并用其他内容重新填充。我应该调用list.clear(),还是只创建一个新的ArrayList,让旧的列表被垃圾收集?每种方法的优缺点是什么?当您想要减少GC上的负载时,保留容器并调用clear:clear()清空数组中的所有引用,但不使数组符合垃圾收集器回收的条件。这可能会加快将来的插入速度,因

清空一个集合(在我的例子中是ArrayList)与创建一个新集合(并让垃圾收集器清除旧集合)相比,有哪些优点和缺点


具体来说,我有一个名为
list
ArrayList
。当某种情况发生时,我需要清空
列表
,并用其他内容重新填充。我应该调用
list.clear()
,还是只创建一个新的
ArrayList
,让旧的列表被垃圾收集?每种方法的优缺点是什么?

当您想要减少GC上的负载时,保留容器并调用
clear
clear()
清空数组中的所有引用,但不使数组符合垃圾收集器回收的条件。这可能会加快将来的插入速度,因为
ArrayList
中的数组不需要增长。当您计划添加到容器中的数据与您清除的数据大小大致相同时,这种方法尤其有利

此外,当其他对象包含对要清除的数组的引用时,您可能需要使用
清除


当新数据的大小可能与以前不同时,释放容器并创建新容器是有意义的。当然,您可以通过调用
clear()
并结合
trimToSize()

来实现类似的效果,这其实并不重要

一个List.clear()实现将内部数组的引用设置为null。如果没有更多引用,则有效地设置要进行垃圾收集的对象

如果你唯一关心的是记忆力,那么这两种方法并没有真正可测量的区别。即使在操作方面,差异也会出现在数组分配(调整大小操作)和其他类似操作中


但是清除它可能会稍微好一点,尽管如果创建一个新的列表更具可读性,我会这样做。

回收
数组列表的好处是(例如,通过调用
清除
)可以避免分配新列表的开销和增加新列表的成本。。。如果您没有提供良好的
初始容量
提示

回收
ArrayList
的缺点包括:

  • clear()
    方法必须将
    null
    分配给
    ArrayList
    s backing数组中的每个(使用的)插槽

  • clear()
    不会调整备份阵列的大小以释放内存。因此,如果您反复填充和清除列表,它将(永久)使用足够的内存来表示遇到的最大列表。换句话说,您增加了内存占用。您可以通过调用
    trimToSize()
    来解决这个问题,但这会创建一个垃圾对象,等等

  • 存在可能影响绩效的地域性和跨代问题。重复回收
    ArrayList
    时,对象及其支持数组可能会被保留。这意味着:

    • 列表对象和表示列表元素的对象可能位于堆的不同区域,这可能会增加TLB未命中和页面流量,特别是在GC时

    • 将(年轻一代)引用分配到(终身)列表的支持数组中可能会产生写屏障开销。。。取决于GC实现

不可能精确地为实际应用程序的性能权衡建模。变量太多了。然而,“公认的智慧”是,如果你有足够的记忆2和一个半体面的垃圾收集器,回收通常不是一个好主意

还值得注意的是,现代JVM可以非常高效地分配对象。它只需要更新堆的“free”指针并写入2或3个对象头字。内存的归零由GC完成。。。除此之外,这项工作大致相当于
clear()
在回收列表中清空引用所做的工作


1-创建一个新的ArrayList比调用clear()然后调用trimToSize(…)对性能更好。使用后者,您将获得垃圾收集开销和多余的零化开销

2-如果垃圾对象与非垃圾对象的比例较高,则复制收集器的效率更高。如果您分析这种收集器的工作方式,几乎所有的成本都是在查找和复制可访问对象时产生的。对垃圾对象需要做的唯一一件事是阻止zero写入清空的“from”空间,以便分配新对象


我的建议是不要回收
ArrayList
对象,除非您有明显的需求来最小化(垃圾)对象创建率;e、 因为这是减少(有害)GC暂停的唯一选择

在所有条件相同的情况下,在现代热点JVM上,我的理解是,通过执行以下操作,您将获得最佳性能:

  • 分配新的ArrayList对象,而不是循环使用
  • 分配列表对象时,请使用准确的
    initialSize
    提示。稍微高估总比稍微低估好

既然有趣的观点已经写好了,你可以更深入地思考

我没有意识到这一点,因为我读了一篇关于破坏者模式的文章,看到了吗

不仅可以重用基础集合,还可以重用集合中的实体

例如,假设生产者和消费者用例。生产者可以一次又一次地将数据填充到同一(循环)数组中,甚至可以使用相同的实体。我只想清除属性