Чому значення кешування класу Integer у діапазоні від -128 до 127?


81

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

Просто цікаво, чому між -128 і 127 ?

У документації Integer.valueOf () зазначено, що вона " кешує часто запитувані значення " . Але чи справді значення між -128та 127часто запитуються? Я думав, що часто запитувані цінності є дуже суб’єктивними.
Чи є якась причина цього?

З документації також зазначено: " ..і може кешувати інші значення поза цим діапазоном. "
Як цього можна досягти?


7
Щодо документації: Oracle просто прикриває свої приклади, якщо пізніше вирішить змінити поведінку. Наприклад, вони можуть вирішити, що Java 9 буде кешувати від -1024 до 1023. Повідомлення полягає в тому, що не покладайтесь на кеш, який містить або не містить будь-яке конкретне ціле число.
Dawood ibn Kareem

7
Я припускаю, що ви повторюєте набагато частіше від 0 до X, ніж від 13476 до Y. Вони, напевно, вирішили, що негативні значення також повинні бути включені, і -128 -> 127 має сенс для підписаного байта.
Jeroen Vannevel

2
Хіба циклічне виконання майже завжди виконується з примітивними ints - не вкладеними в цілі числа? Кешування не застосовується.
брадвідо

2
Кеш - це суто продуктивна річ. Поки це не створює для вас проблеми з продуктивністю, вам не слід хвилювати, який діапазон кешується. (Було б високим глупством вбудувати у ваш код залежність від цілого кешування.)
Hot Licks

3
@JohnR це в специфікації мови Java, див. Відповідь assylias нижче.
Zac Thompson

Відповіді:


105

Просто цікаво, чому між -128 і 127?

Більший діапазон цілих чисел може бути кешований, але принаймні ті між -128 і 127 повинні бути кешовані, оскільки це передбачено специфікацією мови Java (курсив мій):

Якщо значення p, яке вводиться в поле, є істинним, хибним, байтом або символом в діапазоні \ u0000 до \ u007f, або int або коротким числом від -128 до 127 (включно) , то нехай r1 і r2 є результатами будь-які два боксерські перетворення п. Завжди буває так, що r1 == r2.

Обґрунтування цієї вимоги пояснюється в тому ж абзаці:

В ідеалі бокс із заданим примітивним значенням p завжди давав би ідентичне посилання . На практиці це може бути неможливо з використанням існуючих методів реалізації. Наведені вище правила є прагматичним компромісом. Заключний пункт, наведений вище, вимагає, щоб певні загальні значення завжди потрапляли у нерозбірливі об’єкти. [...]

Це гарантує, що в більшості випадків поведінка буде бажаною, без накладення невиправданого покарання за продуктивність, особливо на невеликих пристроях . Менш обмежені в пам'яті реалізації можуть, наприклад, кешувати всі символи та короткі значення, а також значення int і long у діапазоні від -32K до + 32K.


Як я можу кешувати інші значення поза цим діапазоном.?

Ви можете використовувати -XX:AutoBoxCacheMaxопцію JVM, яка насправді не задокументована у списку доступних параметрів точки доступу JVM . Однак це згадується в коментарях всередині Integerкласу навколо рядка 590 :

Розмір кеш-пам'яті може регулюватися -XX:AutoBoxCacheMax=<size>опцією.

Зверніть увагу, що це стосується реалізації та може бути, а може і не бути доступним на інших JVM.


2
Це повна та найкраща відповідь - питання плутає діапазон від -128 до 127 із "часто запитуваними значеннями", хоча насправді вони з різних причин. -128 до 127 зберігаються в кеші для боксу. "часто запитувані значення" кешуються для підвищення продуктивності.
Zac Thompson

@ZacThompson, дякую, що вказали на це. Мій попередній коментар був неправильним. Ключова фраза із специфікації - це "int ... між -128 і 127 (включно), тоді нехай r1 і r2 є результатами будь-яких двох боксерських перетворень р. Завжди так, що r1 == r2". Отже, якщо я правильно розумію, специфікація вимагає, щоб Integer.valueOf (X) == Integer.valueOf (X) де -128 <= X <= 127.
John R

Це єдина відповідь на частину запитання "чому", яка пропонує щось інше, ніж "це за замовчуванням". Однак ця відповідь не є повною, оскільки вона не стосується частини питання "як". Посилання на відповіді інших на XX: AutoBoxCacheMax та додавання інформації про те, як керувати поведінкою кешування в інших реалізаціях JVM (або вказівка, які реалізації JVM мають опції для управління цією поведінкою), зробить це повною відповіддю.
Джон Р

"На практиці це може бути неможливо з використанням існуючих методів реалізації". Я не можу отримати цей рядок. Ви можете пояснити це?
niiraj874u

2
@ niiraj874u Поточна реалізація використовує кеш, який знаходиться в пам'яті - кожне "канонічне" ціле число зберігається в цьому кеші. Тож кешування всіх цілих чисел означало б, що вам, можливо, доведеться зберігати до 2 ^ 32 цілих чисел (= 15+ ГБ) в пам'яті, що є нерозумним, навіть на сучасному настільному комп'ютері.
assylias

22

-128 до 127 - розмір за замовчуванням. Але javadoc також говорить, що розмір кешу цілого числа може регулюватися -XX:AutoBoxCacheMax=<size>параметром. Зверніть увагу, що він встановлює лише високе значення, низьке - завжди -128. Ця функція була введена в 1.6.

Що стосується того, чому від -128 до 127 - це діапазон значень байтів, і природно використовувати його для дуже маленького кешу.


як ми можемо реалізувати -XX:AutoBoxCacheMax=<size>?
DnR

запустіть java -XX: AutoBoxCacheMax = 256 ... і ви побачите, що Integer.valueOf (256) == Integer.valueOf (256)
Євген Дорофєєв

запустивши java -XX:AutoBoxCacheMax=256в консолі, я отримавError:could not create the Java Virtual Machine
DnR

спробуйте java -версія повинна бути 1,6 або вище, моя 1,7 працює нормально
Євген Дорофєєв

2
Правильно, ось чому javadoc каже ..може бути контрольованим ... моя Java - 64 біти
Євген Дорофєєв

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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.