Pergunta

Por que a segunda peça de código é mais rápida?

Map<Integer, Double> map = new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {
        map.put(i, j);
    }
}

Map<Integer, Double> map=new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {            
        map.put(new Integer(i), new Double(j));
    }
}
Foi útil?

Solução

Usos autoboxing Integer.valueOf, que armazenam os objetos inteiros internamente para pequenos números inteiros (por padrão -128 a 127, mas o valor máximo pode ser configurado com a propriedade "java.lang.integer.integercache.high" - consulte o código -fonte do número inteiro.valueof), assim é diferente de ligar new Integer diretamente. Porque Integer.valueOf Uma verificação rápida da magnitude do valor inteiro antes de ligar new Integer, é um pouco mais rápido ligar new Integer diretamente (embora use mais memória se você tiver muitos números inteiros pequenos). A alocação em Java é muito rápida e o tempo que faz o GC é proporcional ao número de objetos de vida curta ao vivo (ou seja, não proporcional à quantidade de lixo), portanto, o GC também é muito rápido.

Mas, dependendo da versão da JVM e de quais otimizações estão ativadas, há a otimização escalar de reposição, que pode produzir uma diferença de desempenho muito maior ao alocar objetos de vida curta (no seu exemplo que a otimização não pode ser feita, porque você está armazenando os objetos em um mapa, mas em muitas outras situações é útil).

Nas versões recentes da JVM, existe substituição escalar otimização (exceto em 1.6.0_18 onde a análise de escape é Temporariamente desativado), o que significa que as alocações de objetos de curta duração podem ser otimizadas. Quando a substituição escalar na JVM era nova, alguém feito uma referência onde havia código semelhante ao seu. O resultado foi que o código que usava primitivos foi mais rápido, o código com explícito new Integer() As chamadas foram quase tão rápidas quanto as primitivas, e o código que usava autoboxing era muito mais lento. Isso foi porque os usos de auto -boxamento Integer.valueOf E pelo menos na época em que a otimização escalar de substituição não levou esse caso especial em consideração. Não sei se a otimização foi melhorada desde então.

Outras dicas

Autoboxing usará Integer.valueOf e Double.valueOf. Há algumas despesas gerais em chamar esses métodos (embora eventualmente fiquem inlinados). Também Integer.valueOf Algumas verificações para que os baixos valores usem instâncias agrupadas, o que não é frequentemente uma vitória no seu código (embora possa reduzir um pouco o tamanho da pilha). Instâncias combinadas podem ser uma vitória em que reduzem o tamanho da pilha, o GC Times e podem até melhorar o desempenho dos testes de igualdade.

Mas, em geral, é uma microoptimização que você deve, em geral, ignorar.

Porque os resultados dos microbenchos não são confiáveis?

Além disso, o boxing automático é feito usando o número inteiro.valueof () e duplo.valueof (), não os construtores.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top