java - 为什么分配单个 2D 数组比循环分配多个总大小和形状相同的 1D 数组花费的时间更长?

标签 java performance

本以为直接创建会更快,但事实上,添加循环只需要一半的时间。到底发生了什么事情速度变慢了?

这是测试代码

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class Test_newArray {
    private static int num = 10000;
    private static int length = 10;

    @Benchmark
    public static int[][] newArray() {
        return new int[num][length];
    }

    @Benchmark
    public static int[][] newArray2() {
        int[][] temps = new int[num][];
        for (int i = 0; i < temps.length; i++) {
            temps[i] = new int[length];
        }
        return temps;
    }

}

测试结果如下。

Benchmark                Mode  Cnt    Score   Error  Units
Test_newArray.newArray   avgt   25  289.254 ± 4.982  us/op
Test_newArray.newArray2  avgt   25  114.364 ± 1.446  us/op

测试环境如下

JMH版本:1.21

虚拟机版本:JDK 1.8.0_212、OpenJDK 64 位服务器虚拟机、25.212-b04

最佳答案

在 Java 中,有一个单独的字节码指令用于分配多维数组 - multianewarray .

  • newArray 基准测试使用 multianewarray 字节码;
  • newArray2 在循环中调用简单的newarray

问题在于 HotSpot JVM 没有用于 multianewarray 字节码的快速路径*。该指令始终在VM运行时执行。因此,分配不会内联在编译的代码中。

第一个基准测试必须付出 Java 和 VM 运行时上下文之间切换的性能损失。此外,VM 运行时中的通用分配代码(用 C++ 编写)并不像 JIT 编译代码中的内联分配那样优化,只是因为它是通用的,即没有针对特定对象类型或对象进行优化对于特定的调用站点,它执行额外的运行时检查等。

以下是使用 async-profiler 分析两个基准的结果。我使用的是 JDK 11.0.4,但对于 JDK 8,图片看起来类似。

newArray

newArray2

第一种情况,99%的时间都花在OptoRuntime::multianewarray2_C里面- VM运行时中的C++代码。

在第二种情况下,图表的大部分是绿色的,这意味着程序主要在 Java 上下文中运行,实际上执行专门针对给定基准优化的 JIT 编译代码。

编辑

* 实际上,HotSpot JVM 可以内联 multianewarray,但前提是分配总数不超过 -XX: MultiArrayExpandLimit 默认为 6。

因此,例如,new int[5][10]将在JIT编译的代码中内联分配,而new int[10][5]的分配code> 将通过 VM 运行时。

关于java - 为什么分配单个 2D 数组比循环分配多个总大小和形状相同的 1D 数组花费的时间更长?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58158445/

相关文章:

Java反射isAccessible方法

mysql - 我可以合理地期望每秒向 MySQL 服务器写入多少次?

performance - 最新至强上的 FP 密集型超线程性能

python - 列表中最长单词的长度

mongodb - MongoDB 聚合 $project 是否会减少内存中保存的数据量?

java - 在通知流上播放声音

java - java中的输出(printf)中的终止符(number).(number)[a](number)[d0]是什么意思?

java - 给定两棵树,如果它们结构相同,则返回 true 它们由具有相同值的节点以相同的方式排列组成

java - 不断获取 "following set of loggers may have been accessed"logback

c++ - 多线程我的程序的负加速