2D阵列分配的性能

时间:2014-06-19 19:14:04

标签: java arrays performance

我想知道为什么一次分配2D int数组(new int[50][2])比分别分配更差,即首先执行new int[50][],然后逐个执行new int[2] 。这是一个非专业的基准代码:

public class AllocationSpeed {

    private static final int ITERATION_COUNT = 1000000;

    public static void main(String[] args) {
        new AllocationSpeed().run();
    }

    private void run() {
        measureSeparateAllocation();
        measureAllocationAtOnce();
    }

    private void measureAllocationAtOnce() {
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int i = 0; i < ITERATION_COUNT; i++) {
            allocateAtOnce();
        }
        stopwatch.stop();
        System.out.println("Allocate at once: " + stopwatch);
    }

    private int allocateAtOnce() {
        int[][] array = new int[50][2];
        return array[10][1];
    }

    private void measureSeparateAllocation() {
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int i = 0; i < ITERATION_COUNT; i++) {
            allocateSeparately();
        }
        stopwatch.stop();
        System.out.println("Separate allocation: " + stopwatch);
    }

    private int allocateSeparately() {
        int[][] array = new int[50][];
        for (int i = 0; i < array.length; i++) {
            array[i] = new int[2];
        }
        return array[10][1];
    }
}

我在64位linux上测试过,这些是不同的64位 oracle java版本的结果:

1.6.0_45-B06:

Separate allocation: 401.0 ms
Allocate at once: 1.673 s

1.7.0_45-B18

Separate allocation: 408.7 ms
Allocate at once: 1.448 s

1.8.0-EA-B115

Separate allocation: 380.0 ms
Allocate at once: 1.251 s

出于好奇,我也尝试使用OpenJDK 7(差异较小):

Separate allocation: 424.3 ms
Allocate at once: 1.072 s

对我而言,这是违反直觉的,我希望立即分配更快。

2 个答案:

答案 0 :(得分:1)

绝对令人难以置信。 基准测试源可能会受到优化,gc和JIT的影响,但是这个?

查看java byte code instruction set

  • anewarray (+ 2字节间接类索引)对象类数组(a =地址)
  • newarray (原始类型数组的+ 1字节)
  • multianewarray (+ 2字节间接类索引)用于多维数组

这导致人们怀疑多重变形对于原始类型来说是次优的。

在进一步观察之前,我希望有人知道我们被误导的地方。

答案 1 :(得分:0)

后一个代码的内部循环(带有newarray)的命中次数比前一个代码的multianewarray更多,因此它可能命中C2并更快地进行转义分析。 (一旦发生,由后一个代码创建的行将分配到堆栈上,这比堆 快,并且减少了垃圾收集器的工作量。)

这些JDK版本也可能实际上没有对multianewarray中的行进行 do 转义分析,因为多维数组更有可能超出堆栈数组的大小限制