我今天偶然发现了这个案子,我想知道这个巨大差异背后的原因是什么。
第一个版本初始化一个5k x 5k的raw int数组:
public void initializeRaw() {
int size = 5000;
int[][] a = new int[size][size];
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
a[i][j] = -1;
}
我的机器大约需要300毫秒。 另一方面,使用简单的2-int结构初始化相同的数组:
public class Struct { public int x; public int y; }
public void initializeStruct() {
int size = 5000;
Struct[][] a = new Struct[size][size];
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
a[i][j] = new Struct();
}
需要超过15000毫秒。
我希望它有点慢,毕竟有更多的内存要分配(如果我没有弄错的话,10个字节而不是4个字节),但是我不明白为什么它需要花费50倍的时间。 / p>
有人可以解释一下吗?也许只有更好的方法在Java中进行这种初始化?
编辑:对于某些比较 - 使用Integer而不是int / Struct的相同代码工作700ms - 只慢两倍。
答案 0 :(得分:4)
我希望它有点慢,毕竟有更多的内存要分配(如果我没有弄错的话,10个字节而不是4个字节),但我不明白为什么它需要花费50倍的时间。
不,比这更糟糕。在第一种情况下,您将创建5001个对象。在第二种情况下,您将创建25,005,001个对象。我怀疑,每个Struct
对象将占用16到32个字节。 (这将取决于各种JVM细节,但这是一个粗略的猜测。)
第一种情况下你的5001个对象总共需要大约100MB。等效对象(数组)可能总共需要大约200MB,如果你在64位引用的平台上......然后那么还有其他2500万个对象需要分配和初始化。
所以是的,差异很大......
答案 1 :(得分:3)
当您创建5000个int的数组时,您将一次性分配所有这些整数所需的所有空间,作为单个连续元素块。为每个数组元素分配一个int时,您没有分配任何内容。与5000个Struct实例的数组形成对比。您遍历该数组,并为这5000个元素中的每一个元素分配一个Struct实例。分配对象比简单地将int值写入变量需要更长的时间。
你有二维数组的事实在这里没有太大的比较差异,因为它只是意味着你在这两种情况下都会分配5000个数组对象。
如果要对一组Integer对象进行计时,然后将每个元素设置为-1,那么每次都不会分配单独的Integer对象。相反,您正在使用自动装箱,这意味着编译器隐式调用Integer.valueOf(-1),并且该方法每次都从缓存中返回相同的对象。
更新:回过头来解决您的问题,如果我理解正确,您需要将5000x5000 Structs保留在2D数组中,并且您对创建此数组比使用原语需要更长时间感到失望。为了提高性能,您可以创建两个基元数组,每个基元一个,但这会降低代码清晰度。
您还可以创建一个long数组(因为每个long的长度是int的两倍)并使用&amp;和&gt;&gt;运营商获得原始的整数。同样,这会降低代码清晰度,但是你只有一个数组。
但是,您似乎专注于代码的单个部分,即数组的创建。您可能会发现,对每个元素执行的处理会使创建数组所花费的时间过多。分析整个应用程序,看看阵列的创建是否重要。