我试图查看预初始化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 ms,而如果我将 List 初始化更改为new ArrayList<Integer>(1000000)
. 为什么会这样?不应该反过来吗?事实上,没有 pre-init 的 List 始终比使用 plain 快一点点(~0.5-1 ms)Integer[]
。基本上,它所说的是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%。但是一些用户似乎得到了正确的行为,所以这很可能是一个非常具体的案例。
EDIT2:如果我使用 String 而不是 Integer 作为元素,则行为是正确的(plain array > pre-capacity-ensured arraylist > default capacity array
)。所以我认为自动装箱实际上是罪魁祸首。