Подтвердить что ты не робот

Автобоксинг против ручного бокса в Java

Почему вторая часть кода быстрее?

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));
    }
}
4b9b3361

Ответ 1

В Autoboxing используется Integer.valueOf, который внутренне кэширует объекты Integer для небольших целых чисел (по умолчанию от -128 до 127, но максимальное значение может быть сконфигурировано с помощью свойства "java.lang.Integer.IntegerCache.high" - см. источник код Integer.valueOf), поэтому он отличается от прямого вызова new Integer. Поскольку Integer.valueOf выполняет быструю проверку величины целочисленного значения перед вызовом new Integer, он немного быстрее вызывает new Integer напрямую (хотя он использует больше памяти, если у вас много маленьких целых чисел). Распределение на Java очень быстро, и время выполнения GC пропорционально количеству живых короткоживущих объектов (т.е. Не пропорционально количеству мусора), поэтому GC также очень быстро.

Но в зависимости от версии JVM и оптимизации которой существует оптимизация скалярной замены, которая может привести к значительно большей разнице в производительности при распределении короткоживущих объектов (в вашем примере оптимизация не может быть выполнена, поскольку вы сохраняете объекты на карте, но во многих других ситуациях это полезно).

В последних версиях JVM существует оптимизация скалярной замены (кроме 1.6.0_18, где escape-анализ временно отключено), что означает, что выделение короткоживущих объектов может быть оптимизировано. Когда скалярная замена в JVM была новой, кто-то сделал тест, где был код, похожий на ваш. В результате код, который использовал примитивы, был самым быстрым, код с явными вызовами new Integer() был почти таким же быстрым, как и тот, который использовал примитивы, а код, который использовал автобоксинг, был намного медленнее. Это объясняется тем, что autoboxing использует Integer.valueOf и, по крайней мере, тогда оптимизация скалярной замены не учитывала этот особый случай. Я не знаю, улучшена ли оптимизация с тех пор.

Ответ 2

Автобоксинг будет использовать Integer.valueOf и Double.valueOf. Есть некоторые накладные расходы при вызове этих методов (хотя в конечном итоге они будут включены). Кроме того, Integer.valueOf выполняет некоторую проверку для низких значений для использования объединенных экземпляров, что нередко является выигрышем в вашем коде (хотя это может немного уменьшить размер кучи). Объединенные экземпляры могут быть победой, где они уменьшают размер кучи, время GC и даже улучшают производительность теста равенства.

Но, в общем, это микрооптимизация, которую вы должны, в общем, игнорировать.

Ответ 3

Потому что результаты микрообъектов ненадежны?

Кроме того, авто-бокс выполняется с использованием Integer.valueOf() и Double.valueOf(), а не конструкторов.