Autoboxing versus boxe manual em Java

Por que o segundo trecho de código é mais rápido?

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

Autoboxing usa Integer.valueOf , que internamente armazena em cache objects Integer para inteiros pequenos (por padrão -128 a 127, mas o valor max pode ser configurado com a propriedade “java.lang.Integer.IntegerCache.high” – veja o código-fonte do Integer .valueOf), por isso é diferente de chamar o new Integer diretamente. Como Integer.valueOf faz uma verificação rápida da magnitude do valor inteiro antes de chamar o new Integer , é um pouco mais rápido chamar diretamente o new Integer (embora ele use mais memory se você tiver muitos inteiros pequenos). A alocação em Java é muito rápida, e o tempo de GC é proporcional ao número de objects vivos de curta duração (ou seja, não proporcional à quantidade de lixo), portanto, o GC também é muito rápido.

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

Em versões recentes da JVM, há otimização de substituição escalar (exceto em 1.6.0_18, em que a análise de escape está temporariamente desativada ), o que significa que as alocações de objects de vida curta podem ser otimizadas. Quando a substituição escalar na JVM era nova, alguém fazia uma referência onde havia código semelhante ao seu. O resultado foi que o código que usava primitivas era mais rápido, o código com new Integer() chamadas explícitas new Integer() era quase tão rápido quanto aquele que usava primitivas, e o código que usava autoboxing era muito mais lento. Isso ocorreu porque a autoboxing usa Integer.valueOf e, pelo menos, a otimização de substituição escalar então não levou esse caso especial em consideração. Não sei se a otimização foi aprimorada desde então.

A checkbox automática usará Integer.valueOf e Double.valueOf . Há alguma sobrecarga em chamar esses methods (embora ele acabe ficando inlined). Também Integer.valueOf faz alguma verificação de valores baixos para usar instâncias agrupadas, o que não é frequentemente uma vitória em seu código (embora possa reduzir um pouco o tamanho de heap). Instâncias agrupadas podem ser uma vitória em que elas reduzem o tamanho de heap, os tempos de GC e podem até melhorar o desempenho do teste de igualdade.

Mas, em geral, é uma micro-otimização que você deve, em geral, ignorar.

Porque os resultados de microbenchmarks não são confiáveis?

Além disso, o auto-boxing é feito usando Integer.valueOf () e Double.valueOf (), não os construtores.