为什么整数类的缓存值在-128到127的范围内?


81

关于我之前的问题,为什么与Integer.valueOf(String)进行==比较会得出127和128的不同结果?,我们知道Integer class有一个缓存用于存储-128和之间的值127

只是想知道为什么在-128和127之间

Integer.valueOf()文档指出,它缓存经常请求的值。但是,-128和之间的值127是否经常被要求是真实的?我认为经常要求的价值观是非常主观的。
这背后有什么可能的原因吗?

从文档中还指出:..并且可能会缓存此范围之外的其他值。
如何实现?


7
请重新阅读文档:Oracle只是在掩盖自己的情况,以防他们以后决定更改行为。例如,他们可能决定Java 9将缓存从-1024到1023。消息是,不依赖于包含或不包含任何特定整数的缓存。
达伍德·伊本·卡里姆

7
我假设您从0到X的循环比从13476到Y的循环要多得多。他们必须确定还应该包含负值,并且-128-> 127对于有符号字节有意义。
Jeroen Vannevel 2014年

2
难道循环几乎总是用原始整数完成的-不是盒装整数吗?缓存不适用。
bradvido 2014年

2
缓存纯粹是性能问题。只要这不会对您造成性能问题,您就不必关心要缓存的范围。(在代码中建立对Integer缓存的依赖将是愚蠢的事情。)
Hot Licks 2014年

3
@JohnR在Java语言规范中,请参阅下面的assylias答案。
扎克·汤普森

Answers:


105

只想知道为什么在-128和127之间?

可能会缓存更大范围的整数,但是至少必须缓存-128到127之间的整数,因为它是Java语言规范(强调我的)所要求的:

如果装箱的值p为true,false,字节或\ u0000到\ u007f范围内的char或-128到127(含)之间的int或short数字,则令r1和r2为结果p的任何两次拳击转换。r1 == r2总是这样。

在同一段中解释了此要求的基本原理:

理想情况下,将给定的原始值p装箱将始终产生相同的参考。实际上,使用现有的实现技术可能不可行。以上规则是务实的妥协。上面的最后一句要求始终将某些通用值装在无法区分的对象中。[...]

这确保了在大多数情况下,行为将是理想的,而不会造成不必要的性能损失,尤其是在小型设备上。例如,较少内存限制的实现可能会缓存所有char和short值,以及-32K到+ 32K范围内的int和long值。


如何缓存超出此范围的其他值?

您可以使用-XX:AutoBoxCacheMaxJVM选项,但未在可用的Hotspot JVM Options列表中真正进行记录。但是,它在Integer590行附近的类内的注释中提到:

高速缓存的大小可由该-XX:AutoBoxCacheMax=<size>选项控制。

请注意,这是特定于实现的,并且在其他JVM上可能可用或不可用。


2
这是一个完整,最佳的答案-该问题将-128至127范围与“经常请求的值”混淆了,而实际上它们是出于不同的原因。-128到127被缓存用于装箱。缓存“经常请求的值”以提高性能。
扎克·汤普森

@ZacThompson,感谢您指出这一点。我之前的评论不正确。规范中的关键短语是“一个int ... -128至127(含)之间,那么让r1和r2为p的任何两次装箱转换的结果。总是r1 == r2的情况。” 因此,如果正确地明白规范强制要求Integer.valueOf(X)==(X),其中-128 <= X <= 127 Integer.valueOf
约翰- [R

这是对问题“为什么”部分提供“默认值”以外的内容的唯一答案。但是,此答案并不完整,因为它没有解决问题的“如何”部分。参考其他人在XX:AutoBoxCacheMax上的响应,并添加有关如何控制JVM其他实现上的缓存行为的信息(或指示哪些JVM实现具有控制此行为的选项),将使这成为一个完整的答案。
约翰R

“实际上,使用现有的实现技术可能不可行。” 我听不到这条线。你能解释一下吗?
niiraj874u 2014年

2
@ niiraj874u当前实现使用驻留在内存中的缓存-每个“规范”整数都保存在该缓存中。因此,缓存所有整数将意味着您可能必须在内存中最多容纳2 ^ 32个整数(= 15+ GB),即使在现代台式计算机上,这也是不合理的。
亚述2014年

22

默认大小为-128至127。但是javadoc还说,Integer缓存的大小可能由该-XX:AutoBoxCacheMax=<size>选项控制。请注意,它仅设置高值,低值始终为-128。此功能在1.6中引入。

至于为什么-128到127-这是字节值范围,很自然地将其用于很小的缓存。


我们如何实施-XX:AutoBoxCacheMax=<size>
DnR 2014年

运行java -XX:AutoBoxCacheMax = 256 ...,您会看到Integer.valueOf(256)== Integer.valueOf(256)
Evgeniy Dorofeev 2014年

通过java -XX:AutoBoxCacheMax=256在控制台中运行,我得到了Error:could not create the Java Virtual Machine
DnR 2014年

尝试java -version,它应该是1.6或更高,我的1.7可以正常工作
Evgeniy Dorofeev 2014年

2
是的,这就是为什么javadoc说..可以被控制的原因...我的Java是64位
Evgeniy Dorofeev 2014年

5

缓存小整数的原因(如果您要这样)是因为许多算法在计算中都使用小整数,因此避免这些值的对象创建开销往往是值得的。

然后问题变成要缓存哪些整数。再说一次,通常来说,使用常数的频率会随着常数的绝对值的增加而降低-每个人都花很多时间使用值1或2或10,很少几个人使用值109密集地 更少的性能取决于获得722整数的速度。Java选择分配256个跨越有符号字节值范围的插槽。可以通过分析当时存在的程序来告知此决定,但可能完全是任意决定。这是一个合理的投资空间,可以快速访问(掩码以查找值是否在缓存的范围内,然后通过快速表查找来访问缓存),并且它肯定会涵盖最常见的情况。

换句话说,我认为您的问题的答案是“它不像您想的那样主观,但是确切的界限很大程度上是基于经验法则的决定……而实验证据表明,这一点已经足够好了。 ”


3

可以通过系统属性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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.