list.clear() 与 list = new ArrayList<Integer>(); [复制]
Posted
技术标签:
【中文标题】list.clear() 与 list = new ArrayList<Integer>(); [复制]【英文标题】:list.clear() vs list = new ArrayList<Integer>(); [duplicate] 【发布时间】:2011-10-21 03:22:03 【问题描述】:这两个选项中哪一个更好更快地清除 ArrayList,为什么?
list.clear()
或
list = new ArrayList<Integer>();
碰巧我必须随机清除 ArrayList 中的所有条目,我无法知道将来会有多少新条目,可能是 0 或 1000。哪种方法更快更好,为什么?
【问题讨论】:
它们是不同的。使用适合的任务。因为我喜欢尽量减少副作用,所以我经常选择后者。在这里担心“性能”是......可能很愚蠢。 如何在泛型中使用原始类型?您必须使用包装类。 您是否进行过任何基准测试?这将是找出答案的最佳方式。 答案也可能取决于您是否共享您的列表。如果它是一个共享列表,那么其他使用它的人可能会惊讶于你调用 clear 后它是空的。但是,如果您分配一个新列表,它不会摆脱引用(如果第一个列表是共享的) 【参考方案1】:如果没有基准就很难知道,但是如果 ArrayList 中有很多项目并且平均大小较小,那么创建一个新的 ArrayList 可能会更快。
http://www.docjar.com/html/api/java/util/ArrayList.java.html
public void clear()
modCount++;
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
【讨论】:
+1 用于显示来源。有趣的是,clear
不会调整后备数组的大小。
@pst:这是一个有趣的点——如果要清除 ArrayList 并重复地重新填充数百个项目,使用 .clear()
可能会更快,从而防止数组复制当大小超过.add(Object)
调用的容量时发生。
注意,一个新的 ArrayList 也需要 O(n) 时间 - new Object[n] 需要为每个槽清零。
@PlatinumAzure:这并不是明确的优势,因为您可以设置 ArrayList 的初始容量?
@irreputable - 但是,一个区别是 clear() 使用显式循环执行操作(在 Java 中),但对于 new Object[n]
,归零是由 GC 使用大容量内存归零机制完成的人们期望更快;例如手动优化的 C++ 或 ASM,甚至是巧妙的虚拟内存技巧。【参考方案2】:
List.clear
将删除元素而不减少列表的容量。
groovy:000> mylist = [1,2,3,4,5,6,7,8,9,10,11,12]
===> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
groovy:000> mylist.elementData.length
===> 12
groovy:000> mylist.elementData
===> [Ljava.lang.Object;@19d6af
groovy:000> mylist.clear()
===> null
groovy:000> mylist.elementData.length
===> 12
groovy:000> mylist.elementData
===> [Ljava.lang.Object;@19d6af
groovy:000> mylist = new ArrayList();
===> []
groovy:000> mylist.elementData
===> [Ljava.lang.Object;@2bfdff
groovy:000> mylist.elementData.length
===> 10
这里 mylist 被清除,对它持有的元素的引用被清空,但它保持相同的后备数组。然后 mylist 被重新初始化并得到一个新的后备数组,旧的得到了 GCed。因此,一种方式保留内存,另一种方式丢弃其内存并从头开始重新分配(使用默认容量)。哪个更好取决于您是要减少垃圾收集流失还是要最小化当前未使用的内存量。列表是否存在足够长的时间以移出 Eden 可能是决定哪个更快的一个因素(因为这可能会使垃圾收集成本更高)。
【讨论】:
【参考方案3】:我认为答案取决于一系列因素,例如:
是否可以预先预测列表大小(即是否可以准确设置容量), 列表大小是否可变(即每次填充), 两个版本中列表的生命周期是多长,以及 您的堆/GC 参数和 CPU。这些使得很难预测哪个会更好。但我的直觉是,差别不会那么大。
关于优化的两条建议:
不要浪费时间尝试优化...除非应用程序客观上太慢了AND使用profiler 告诉你这是一个性能热点。 (很可能其中一个前提条件不成立。)
如果您决定对此进行优化,请科学地进行。尝试两种(所有)替代方案,并通过测量实际应用程序在实际问题/工作负载/输入集上的性能来决定哪个是最好的。 (由于我之前列出的因素,人工基准可能会给出无法预测真实行为的答案。)
【讨论】:
【参考方案4】:第一个.clear();
将保持相同的列表只是清除列表。
第二个new ArrayList<Integer>();
在内存中创建一个新的ArrayList
。
建议:第一个,因为这是设计的目的。
【讨论】:
当然,clear
旨在清除列表 - 但从根本上说,这比使用 new 空列表更好吗?
实际上,它不会在内存中创建新的ArrayList,而是替换旧的列表。它不会使用更多的内存。旧列表将被转储。
@RicardoFiorani 答案并没有说它会使用更多。它确实会在内存中创建一个新的 ArrayList,在旧的 ArrayList 被垃圾回收之前,旧的内存不会被重新使用。
@RMT :答案听起来无可争议。
当然,如果列表很大,一个明确的帮助java知道可以使用gc(没有保证),创建一个新列表可能比循环一个大的更快,但是你在内存中保存了很多对象(大列表),也许很多时间。无论如何,使用 clear 和 "trimtoSize()" 方法用真实值(不是旧值大小)更新 size 属性【参考方案5】:
尝试了以下程序,两种方法。 1.在for循环中清除arraylist obj 2. 在 for 循环中创建新的 New Arraylist。
List al= new ArrayList();
for(int i=0;i<100;i++)
//List al= new ArrayList();
for(int j=0;j<10;j++)
al.add(Integer.parseInt("" +j+i));
//System.out.println("Obj val " +al.get(j));
//System.out.println("Hashcode : " + al.hashCode());
al.clear();
令我惊讶的是。内存分配没有太大变化。
采用新的 Arraylist 方法。
循环前总可用内存:64,909 ::
循环后总可用内存:64,775 ::
采用清晰的方法,
循环前总可用内存:64,909 :: 循环后总可用内存:64,765 ::
所以这说明从内存利用率的角度来看,使用 arraylist.clear 并没有太大区别。
【讨论】:
恕我直言 10 和 100 太小了,无法测试。 内存使用不应该有任何差异,因为您最终只没有外部 ArrayList 而不是垃圾收集。这根本没有解决问题中的性能问题,这不是答案。【参考方案6】:如果列表很有可能在清除它时包含与其包含的元素一样多的元素,并且如果您不需要空闲内存,那么清除列表是一个更好的选择。但我的猜测是,这可能无关紧要。在检测到性能问题并确定问题的根源之前,不要尝试优化。
【讨论】:
关于过早优化的要点。【参考方案7】:list.clear()
将保持相同的 ArrayList 但相同的内存分配。 list = new ArrayList<int>();
将为您的 ArrayList 分配新内存。
最大的不同是 ArrayList 会随着您需要更多空间而动态扩展。因此,如果您调用 list.clear()
,您仍然可能会为可能不需要的 ArrayList 分配大量内存。
也就是说list.clear()
会更快,但如果内存充足,您可能需要分配一个新的 ArrayList。
【讨论】:
【参考方案8】:我建议使用 list.clear() 而不是分配一个新对象。当您调用“new”关键字时,您会在内存中创建更多空间。实际上,这并不重要。我想如果你知道列表有多大,创建一个新空间然后指定数组有多大可能是个好主意。
事实是,除非您进行科学编程,否则这无关紧要。这种情况下,你需要去学习 C++。
【讨论】:
以上是关于list.clear() 与 list = new ArrayList<Integer>(); [复制]的主要内容,如果未能解决你的问题,请参考以下文章
Java list1=list2;list2=null ? list1=list2;list2.clear()?
Java list1=list2;list2=null ? list1=list2;list2.clear()?