java - 删除并重新创建数组或用零填充它是否更快,为什么?

标签 java memory-management garbage-collection jvm

假设我创建了一个旨在模拟处理器内存的数组:

byte[] mem = new byte[0xF00];

此数组在仿真操作过程中使用,最终(读取:频率)需要丢弃或重置。我的问题是,哪个更快,为什么?

mem = new byte[0xF00];

或:

for(int i = 0; i < mem.length; i++) mem[i] = 0;

这可能看起来并不重要,但在模拟大量处理器时,小的效率会产生影响。速度上的差异将来自 JVM 的垃圾收集;一方面,数组必须被转储和垃圾收集,然而,JVM 不再需要分配(并且可能清零?)新内存。第二种,避免了 JVM 成本,但我们仍然必须遍历数组中的每个元素。

作为对这个问题的额外警告:

  1. 成本比率是否随数据类型的大小而变化?例如,short[] 怎么样?
  2. 阵列的长度是否影响成本比率?
  3. 最重要的是,为什么?

最佳答案

您可以自己测试,但删除和重新创建数组大致相同。

但是,它有两个缺点

  • 它会导致您的 CPU 数据缓存滚动,从而降低其效率。
  • 它更有可能触发 GC,尤其是如果您经常这样做,这会暂停系统或减慢系统速度(如果它是并发的)

我更喜欢重用数组,不是因为它最快,而是因为它对应用程序的其余部分的影响最小。


for (int size = 16; size <= 16* 1024; size *= 2) {
    int count1 = 0, count1b = 0,count2 = 0;
    long total1 = 0, total1b = 0, total2 = 0;
    for (long i = 0; i < 10000000000L; i += size) {
        long start = System.nanoTime();
        long[] longs = new long[size];
        if (longs[0] + longs[longs.length - 1] != 0)
            throw new AssertionError();
        long mid = System.nanoTime();
        long time1 = mid - start;
        Arrays.fill(longs, 1L);
        long time2 = System.nanoTime() - mid;
        count1b++;
        total1b += time1;
        if (time1 < 10e3) {// no GC
            total1 += time1;
            count1++;
        }
        if (time2 < 10e3) {// no GC
            total2 += time2;
            count2++;
        }
    }
    System.out.printf("%s KB took on average of %,d ns to allocate, %,d ns to allocate including GCs and %,d ns to fill%n",
            size * 8 / 1024.0, total1 / count1, total1b/count1b, total2 / count2);
}

打印

0.125 KB took on average of 35 ns to allocate, 36 ns to allocate including GCs and 19 ns to fill
0.25 KB took on average of 39 ns to allocate, 40 ns to allocate including GCs and 31 ns to fill
0.5 KB took on average of 56 ns to allocate, 58 ns to allocate including GCs and 55 ns to fill
1.0 KB took on average of 75 ns to allocate, 77 ns to allocate including GCs and 117 ns to fill
2.0 KB took on average of 129 ns to allocate, 134 ns to allocate including GCs and 232 ns to fill
4.0 KB took on average of 242 ns to allocate, 248 ns to allocate including GCs and 368 ns to fill
8.0 KB took on average of 479 ns to allocate, 496 ns to allocate including GCs and 644 ns to fill
16.0 KB took on average of 1,018 ns to allocate, 1,055 ns to allocate including GCs and 1,189 ns to fill
32.0 KB took on average of 2,119 ns to allocate, 2,200 ns to allocate including GCs and 2,625 ns to fill
64.0 KB took on average of 4,419 ns to allocate, 4,604 ns to allocate including GCs and 4,728 ns to fill
128.0 KB took on average of 8,333 ns to allocate, 9,472 ns to allocate including GCs and 8,685 ns to fill

仅证明很难假设一种方法在所有情况下都比另一种更快。

如果我将 long[] 更改为 int[],我看到的结果大致相同

0.125 KB took on average of 35 ns to allocate, 36 ns to allocate including GCs and 16 ns to fill
0.25 KB took on average of 40 ns to allocate, 41 ns to allocate including GCs and 24 ns to fill
0.5 KB took on average of 58 ns to allocate, 60 ns to allocate including GCs and 40 ns to fill
1.0 KB took on average of 86 ns to allocate, 87 ns to allocate including GCs and 94 ns to fill
2.0 KB took on average of 139 ns to allocate, 143 ns to allocate including GCs and 149 ns to fill
4.0 KB took on average of 256 ns to allocate, 262 ns to allocate including GCs and 206 ns to fill
8.0 KB took on average of 472 ns to allocate, 481 ns to allocate including GCs and 317 ns to fill
16.0 KB took on average of 981 ns to allocate, 999 ns to allocate including GCs and 516 ns to fill
32.0 KB took on average of 2,098 ns to allocate, 2,146 ns to allocate including GCs and 1,458 ns to fill
64.0 KB took on average of 4,312 ns to allocate, 4,445 ns to allocate including GCs and 4,028 ns to fill
128.0 KB took on average of 8,497 ns to allocate, 9,072 ns to allocate including GCs and 7,141 ns to fill

关于java - 删除并重新创建数组或用零填充它是否更快,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16162185/

相关文章:

java - SimpleDateFormat 解析后给出错误的输出

c - 二指针表示困境

java - 由于源 1.5,无法构建包目标

hibernate - 在 J2SE 应用程序中从 persistence.xml 外部化凭据

iphone - iPhone 的 NSXMLParser 内存分配效率

c++ - 在这种情况下如何管理内存

c# - 短时间内防止 .NET 垃圾收集

cocoa - Xcode Cocoa 中的垃圾收集在哪里?

java - 在 Android/Java 中格式化 MAC 地址而不会产生不必要的垃圾

java - 从签名的 java applet 中删除文件