Pourquoi ne l'allocation d'une prise de tableau 2D unique plus d'une boucle allocation des réseaux multiples 1D de la même taille totale et la forme?


user10339780:

Je pensais que ce serait plus rapide de créer directement, mais en fait, en ajoutant des boucles prend seulement la moitié du temps. Ce qui est arrivé qui a ralenti tant?

Voici le code de test

@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;
    }

}

Les résultats des tests sont les suivants.

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

L'environnement de test est la suivante

Version JMH: 1,21

VM version: JDK 1.8.0_212, OpenJDK 64 bits serveur VM, 25,212-B04

apangin:

En Java il y a une instruction de bytecode séparée pour l' attribution des tableaux multidimensionnels - multianewarray.

  • newArrayUtilisations de référence multianewarraybytecode;
  • newArray2invoque simple , newarraydans la boucle.

Le problème est que machine virtuelle Java HotSpot a pas de chemin rapide * pour multianewarraybytecode. Cette instruction est toujours exécutée dans l' exécution VM. Par conséquent, l'allocation n'est pas inline dans le code compilé.

Le premier indice de référence a à la peine de rémunération au rendement de la commutation entre les contextes Java et VM Runtime. En outre, le code d'allocation commune dans le moteur d' exécution VM (écrit en C ++) n'est pas aussi optimisé que l' allocation inline dans le code compilé JIT, juste parce qu'il est générique , à savoir pas optimisé pour le type d'objet particulier ou pour le site d'appel particulier, effectue des contrôles d'exécution supplémentaires, etc.

Voici les résultats de profilage avec les deux points de référence async-profileur . Je 11.0.4 JDK, mais pour l'image 8 JDK ressemble.

newArray

newArray2

Dans le premier cas, le temps de 99% est passé à l' intérieur OptoRuntime::multianewarray2_C- le code C ++ dans le runtime VM.

Dans le second cas, la majeure partie du graphique est vert, ce qui signifie que le programme se déroule la plupart du temps dans le contexte Java, exécuter réellement le code compilé JIT optimisé spécifiquement pour l'indice de référence donné.

ÉDITER

* Juste pour clarifier: en HotSpot multianewarrayn'est pas très bien optimisé par la conception. Il est assez coûteux à mettre en œuvre une telle opération complexe dans les deux compilateurs JIT correctement, alors que les avantages d' une telle optimisation seraient discutables: répartition des tableaux est rarement multidimentionnelle un goulot d'étranglement dans une application typique.

Articles connexes