Почему значения кеширования целочисленного класса находятся в диапазоне от -128 до 127?

81

Что касается моего предыдущего вопроса, почему == сравнения с Integer.valueOf (String) дают разные результаты для 127 и 128? , мы знаем, что у Integer classнего есть кеш, в котором хранятся значения между -128и 127.

Просто интересно, почему между -128 и 127 ?

В документации Integer.valueOf () указано, что он « кэширует часто запрашиваемые значения » . Но часто ли запрашиваются значения между -128и 127на самом деле? Я думал, что часто запрашиваемые значения очень субъективны.
Есть ли какая-то возможная причина?

Из документации также говорится: «..и может кэшировать другие значения вне этого диапазона »
Как это может быть достигнуто?

DnR
источник
7
Обратитесь к документации: Oracle просто прикрывает свои задницы на случай, если позже решит изменить поведение. Например, они могут решить, что Java 9 будет кэшировать от -1024 до 1023. Сообщение состоит в том, что не полагайтесь на кеш, содержащий или не содержащий какое-либо конкретное целое число.
Давуд ибн Карим
7
Я предполагаю, что вы намного чаще выполняете цикл от 0 до X, чем от 13476 до Y. Они, должно быть, решили, что отрицательные значения также должны быть включены и -128 -> 127 имеет смысл для подписанного байта.
Jeroen Vannevel
2
Разве цикл почти всегда не выполняется с примитивными целыми числами, а не с целыми числами в коробке? Кеширование не применяется.
bradvido 03
2
Кеш - это чисто производительность. Пока это не создает для вас проблем с производительностью, вам все равно, какой диапазон кэшируется. (Было бы верхом глупости встроить в свой код зависимость от целочисленного кеширования.)
Hot Licks
3
@JohnR это в спецификации языка Java, см. Ответ ассилий ниже.
Зак Томпсон

Ответы:

105

Просто интересно, почему между -128 и 127?

Можно кэшировать больший диапазон целых чисел , но, по крайней мере, числа между -128 и 127 должны быть кэшированы, потому что это предусмотрено Спецификацией языка Java (выделено мной):

Если упаковываемое значение p равно true, false, байту или символу в диапазоне от \ u0000 до \ u007f, либо int или короткому числу от -128 до 127 (включительно) , тогда пусть r1 и r2 будут результатами любые два боксерских преобразования p. Всегда бывает так, что r1 == r2.

Обоснование этого требования объясняется в том же параграфе:

В идеале упаковка данного примитивного значения p всегда давала бы идентичную ссылку . На практике это может оказаться невозможным при использовании существующих методов реализации. Приведенные выше правила представляют собой прагматический компромисс. Последнее предложение выше требует, чтобы определенные общие значения всегда помещались в неразличимые объекты. [...]

Это гарантирует, что в большинстве распространенных случаев поведение будет желаемым, без чрезмерного снижения производительности, особенно на небольших устройствах . Реализации с меньшим ограничением памяти могут, например, кэшировать все значения char и short, а также значения int и long в диапазоне от -32K до + 32K.


Как я могу кэшировать другие значения за пределами этого диапазона?

Вы можете использовать параметр -XX:AutoBoxCacheMaxJVM, который на самом деле не задокументирован в списке доступных параметров JVM Hotspot . Однако это упоминается в комментариях внутри Integerкласса около строки 590 :

Размер кеша может контролироваться -XX:AutoBoxCacheMax=<size>опцией.

Обратите внимание, что это зависит от реализации и может быть или недоступен на других JVM.

ассилий
источник
2
Это полный и лучший ответ - вопрос путает диапазон от -128 до 127 с «часто запрашиваемыми значениями», хотя на самом деле это происходит по разным причинам. -128 до 127 кешируются для бокса. «часто запрашиваемые значения» кэшируются для повышения производительности.
Зак Томпсон,
@ZacThompson, спасибо, что указали на это. Мой предыдущий комментарий был неверным. Ключевая фраза из спецификации: «int ... от -128 до 127 (включительно), тогда пусть r1 и r2 будут результатами любых двух упаковочных преобразований p. Всегда бывает так, что r1 == r2». Итак, если я правильно понимаю, спецификация требует, чтобы Integer.valueOf (X) == Integer.valueOf (X), где -128 <= X <= 127.
Джон Р.
Это единственный ответ на часть вопроса «почему», который предлагает нечто иное, чем «это значение по умолчанию». Однако этот ответ неполный, потому что он не касается части вопроса «как». Ссылка на ответы других пользователей на XX: AutoBoxCacheMax и добавление информации о том, как управлять поведением кэширования в других реализациях JVM (или указание, какие реализации JVM имеют параметры для управления этим поведением) сделают это полным ответом.
John R
«На практике это может оказаться невозможным при использовании существующих методов реализации». Я не могу понять эту строку. Не могли бы вы объяснить это?
niiraj874u
2
@ niiraj874u Текущая реализация использует кеш, который находится в памяти - каждое "каноническое" целое число хранится в этом кеше. Таким образом, кеширование всех целых чисел может означать, что вам, возможно, придется хранить в памяти до 2 ^ 32 целых чисел (= 15+ ГБ), что неразумно даже на современном настольном компьютере.
assylias
22

От -128 до 127 - размер по умолчанию. Но javadoc также говорит, что размер целочисленного кеша может контролироваться -XX:AutoBoxCacheMax=<size>опцией. Обратите внимание, что он устанавливает только высокое значение, низкое значение всегда -128. Эта функция была представлена ​​в версии 1.6.

Что касается того, почему от -128 до 127 - это диапазон значений байтов, и его естественно использовать для очень маленького кеша.

Евгений Дорофеев
источник
как мы можем реализовать -XX:AutoBoxCacheMax=<size>?
DnR 03
запустите java -XX: AutoBoxCacheMax = 256 ... и вы увидите, что Integer.valueOf (256) == Integer.valueOf (256)
Евгений Дорофеев
запустив java -XX:AutoBoxCacheMax=256консоль, я получилError:could not create the Java Virtual Machine
DnR 03
попробуйте java -version, он должен быть 1.6 или выше, мой 1.7 работает нормально
Евгений Дорофеев
2
Правильно, поэтому javadoc говорит ... можно контролировать ... у меня 64-битная Java
Евгений Дорофеев
5

Причина кеширования небольших целых чисел, если вы об этом спрашиваете, заключается в том, что многие алгоритмы используют в своих вычислениях небольшие целые числа, поэтому, как правило, стоит избегать накладных расходов на создание объектов для этих значений.

Тогда возникает вопрос, какие целые числа кэшировать. Опять же, говоря в целом, частота, с которой используются постоянные значения, имеет тенденцию к уменьшению по мере увеличения абсолютного значения константы - каждый тратит много времени, используя значения 1, 2 или 10, относительно немногие используют значение 109 очень интенсивно; меньшее количество будет иметь производительность в зависимости от того, как быстро можно получить целое число для 722. Java решила выделить 256 слотов, охватывающих диапазон значений байта со знаком. Это решение могло быть основано на анализе программ, существовавших в то время, но столь же вероятно, что оно было чисто произвольным. Это разумный объем места для инвестиций, к нему можно быстро получить доступ (маска, чтобы узнать, находится ли значение в диапазоне кеша, затем быстрый поиск в таблице для доступа к кешу), и он определенно охватывает наиболее распространенные случаи.

Другими словами, я думаю, что ответ на ваш вопрос таков: «это не так субъективно, как вы думали, но точные границы в значительной степени являются практическим решением ... и экспериментальные доказательства показали, что это было достаточно хорошо. "

кешлам
источник
3

Максимальное максимальное целочисленное значение, которое можно кэшировать, можно настроить с помощью системного свойства ie java.lang.Integer.IntegerCache.high( -XX:AutoBoxCacheMax). Кеш реализован с помощью массива.

    private static class IntegerCache {
    static final int high;
    static final Integer cache[];

    static {
        final int low = -128;

        // high value may be configured by property
        int h = 127;
        if (integerCacheHighPropValue != null) {
            // Use Long.decode here to avoid invoking methods that
            // require Integer's autoboxing cache to be initialized
            int i = Long.decode(integerCacheHighPropValue).intValue();
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - -low);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

    private IntegerCache() {}
}
время экзамена
источник
0

Когда вы сталкиваетесь с классом Integer и всегда помещаете в коробку в диапазоне от -128 до 127, всегда лучше преобразовать объект Integer в значение int, как показано ниже.

<Your Integer Object>.intValue()
Teja
источник