Eu pensei que seria mais rápido para criar diretamente, mas na verdade, a adição de laços leva apenas metade do tempo. O que aconteceu que abrandou tanto?
Aqui está o código de teste
@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;
}
}
Os resultados do teste são como se segue.
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
O ambiente de teste é como se segue
versão JMH: 1,21
VM versão: JDK 1.8.0_212, OpenJDK 64-Bit Servidor VM, 25.212-b04
Em Java há uma instrução bytecode separado para alocação de arrays multidimensionais - multianewarray
.
newArray
Utilizações de referênciamultianewarray
bytecode;newArray2
invoca simplesnewarray
no circuito.
O problema é que HotSpot JVM tem nenhum caminho rápido * para multianewarray
bytecode. Esta instrução é sempre executada na VM de tempo de execução. Portanto, a alocação não está embutido no código compilado.
A primeira referência tem de penalidade de desempenho de pagamento de alternar entre contextos Java e VM de tempo de execução. Além disso, o código de atribuição comum no tempo de execução de VM (escrita em C ++) não é tão optimizado quanto atribuição indexados num código compilado-JIT, apenas porque é genérico , ou seja, não optimizada para o tipo de objecto específico ou para o local de chamada especial, realiza verificações de tempo de execução adicionais, etc.
Aqui estão os resultados de profiling ambos os benchmarks com async-profiler . Eu costumava JDK 11.0.4, mas para JDK 8 o quadro é semelhante.
No primeiro caso, 99% do tempo gasto no interior OptoRuntime::multianewarray2_C
- o código C ++ no tempo de execução VM.
No segundo caso, a maior parte do gráfico é verde, o que significa que o programa é executado principalmente no contexto de Java, na verdade, a execução do código compilado-JIT optimizado especificamente para o referencial dado.
EDITAR
* Só para esclarecer: em HotSpot multianewarray
não é otimizado muito bem por design. É bastante caro para implementar uma operação tão complexa em ambos os compiladores JIT corretamente, enquanto os benefícios de tal otimização seria questionável: alocação de matrizes multidimensional raramente é um gargalo de desempenho em uma aplicação típica.