我试图查看预先初始化ArrayList
到给定容量与使用默认容量并根据需要扩展之间的性能差异。只是出于好奇。我发现,默认容量数组代码比将数组初始化为所需容量的代码快大约10%。这是我使用的代码:
public class Test {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
for(int j=0;j<10;++j) {
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<1000000;++i) {
list.add(i);
}
}
long t2 = System.currentTimeMillis();
System.out.println("Time taken: " + (t2-t1)/10.0);
}
}
我在我的电脑上始终得到大约77毫秒的结果,如果我将List初始化更改为
new ArrayList<Integer>(1000000)
,则得到大约85毫秒。为什么会这样?难道不应该相反吗?实际上,没有预初始化的List比使用普通的Integer[]
稍微快一点(约0.5-1毫秒)。基本上,它表明在插入性能方面,default capacity arraylist > simple array > pre-capacity-ensured arraylist
。这对我来说非常奇怪。我的初步猜测是它与内存分配有关,例如一次性给出1000000个int块可能比缓慢获取更多空间要慢?这在其他机器上可重现吗?我正在使用jdk 1.6.0,Mac OS X,通过eclipse运行。
我在另外两个环境中尝试过: -->尝试从命令行而不是eclipse运行java+javac - 在这里,我始终得到
pre-capacity-ensured arraylist > simple array > default capacity arraylist
。
-->在我的Linux(RHEL)桌面上运行java+javac。这台机器有24 GB RAM,而我的笔记本电脑只有8 GB。在这里,我得到plain array >>> default capacity arraylist > pre-capacity-ensured arraylist
。在这种情况下,普通数组非常快,大约比其他两个快2-3倍。
编辑:根据@JonSkeet在评论中的建议,我使用了nanoTime()
和Integer
而不是int
。但它仍然没有解决JIT预热未被考虑的问题。在这些更改之后,我始终看到普通数组在所有测试中都是最快的。但是,对于我来说,在所有上述3个环境中,容量保证列表仍然比默认容量列表慢5-10%。但是有些用户似乎得到了正确的行为,所以这可能是一个非常特定的情况。
编辑2:如果我将元素替换为String,则行为是正确的(plain array > pre-capacity-ensured arraylist > default capacity array
)。因此,自动装箱实际上是罪魁祸首。
currentTimeMillis
而不是nanoTime
。请尝试使用https://code.google.com/p/caliper/ - 另外,我怀疑您测试的大部分时间都花费在将一百万个int
值封装成对象上。请尝试使用不需要在每次迭代中创建新对象的东西进行测试。 - Jon SkeetList<String>
和一些文字即可将其排除在外。) - Jon Skeet