【问题标题】:Why is creating ArrayList with initial capacity slow?为什么创建初始容量的 ArrayList 很慢?
【发布时间】:2016-08-05 16:05:13
【问题描述】:

将创建大型 ArrayList 与 intialCapacity 进行比较,我发现它比没有创建大型 ArrayList 慢。这是我编写的用于测量它的简单程序:

long start2 = System.nanoTime();
List<Double> col = new ArrayList<>(30000000); // <--- Here
for (int i = 0; i < 30000000; i++) {
    col.add(Math.sqrt(i + 1));
}
long end2 = System.nanoTime();
System.out.println(end2 - start2);
System.out.println(col.get(12411325).hashCode() == System.nanoTime());

ArrayList&lt;&gt;(30000000)的平均结果:6121173329

ArrayList&lt;&gt;()的平均结果:4883894100

在我的机器上。我认为一旦超出当前底层数组ArrayList 的容量,创建一次大型数组而不是重新创建它会更快。最终我们应该得到大于或等于30000000 的数组大小。

我以为是优化,其实是悲观。为什么会这样?

【问题讨论】:

  • @ManoDestra 那么,初始容量的用途是什么,何时使用?
  • 当您添加30,000,000th 元素时,List 扩展为60,000,000 元素。尝试将初始容量增加1(但不要在List 中添加其他数字)。
  • @ManoDestra 如果它恰好for lopp 之后的列表大小,那么“高”是怎么来的?如果 OPs 的发现确实是真的,我会感到惊讶,因为如果没有设置初始容量,ArrayList 将不得不重新分配和复制自身 ceil(log2(30000000/10)) = 22 次,最终内部容量为 41943040,超过 30%太多了。
  • @ElliottFrisch 如果你能挖掘出编写的源代码,这将是一个很好的答案!
  • 如果您正在做一个小型基准测试,我建议您通读这个问题:stackoverflow.com/questions/504103/…

标签: java arraylist


【解决方案1】:

我多次运行同一个程序。它不是在循环中

考虑如何分析代码 - 如果同时包含 “加速时间”(考虑到诸如 JIT 等因素)和 平均在多次调用(收集一些统计数据/分布)后,时间可能会导致您得出不同的结论。例如:

public static void main(String[] args){
    //Warm up
    System.out.println("Warm up");
    for ( int i = 0; i < 5; i++ ){
        dynamic();
        constant();
    }
    System.out.println("Timing...");
    //time
    long e = 0;
    long s = 0; 
    int total = 5;
    for ( int i = 0; i < total; i++ ){
        long e1 = dynamic();
        System.out.print(e1 + "\t");
        e += e1;
        long s1 = constant();
        System.out.println(s1);
        s += s1;
    }
    System.out.println("Static Avg: " + (s/total));
    System.out.println("Dynamic Avg: " + (e/total));

}

private static long dynamic(){
    long start2 = System.currentTimeMillis();
    List<Double> col = new ArrayList<>();
    for (int i = 0; i < 30000000; i++) {
        col.add(Math.sqrt(i + 1));
    }
    long end2 = System.currentTimeMillis();
    return end2 - start2;
}

private static long constant(){
    long start2 = System.currentTimeMillis();
    List<Double> col = new ArrayList<>(30000000); 
    for (int i = 0; i < 30000000; i++) {
        col.add(Math.sqrt(i + 1));
    }
    long end2 = System.currentTimeMillis();
    return end2 - start2;
}

在我的系统设置中,初始容量总是更快,尽管不是任何数量级。

编辑:根据评论中的建议,考虑阅读How do I write a correct micro-benchmark in Java?

【讨论】:

  • 我的结果:静态平均:7544;动态平均:2379 !?
  • 考虑 a) 不仅是平均值,还有分布 b) 编辑链接中的规则(我的代码不一定遵守所有规则)
猜你喜欢
  • 2016-08-27
  • 2015-04-05
  • 2013-03-04
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
相关资源
最近更新 更多