从JDK源码理解Java Integer的缓存机制
Posted ybdesire
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从JDK源码理解Java Integer的缓存机制相关的知识,希望对你有一定的参考价值。
1. 引入
参考1中给出了一段很有趣的代码如下,运行会输出什么呢?
Integer a1 = 9;
Integer b1 = 9;
System.out.println(a1==b1);//true
Integer x = 396;
Integer y = 396;
System.out.println(x==y);//false
按照常理,a1和b1都由auto-boxing机制,new出了两个不同的对象,那a1就不可能等于b1(reference);x和y同理,应该都输出false才符合“语法逻辑”。但是,答案也很奇怪:第一个println输出的是true,第二个是false,这是为什么呢?
2. Integer的cache
从javadoc中(参考2中valueOf(int i)的说明),我们可以看到Integer有自己设计的缓存机制:
this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
首先,为什么要看valueOf()的实现呢?因为1中的代码是auto-boxing的机制来new Integer对象的,而auto-boxing就是用valueOf来实现的(详见参考4)。
然后,我们从javadoc的描述中,发现Integer它会对一些常用的int值进行缓存,而不是对任何int值都new一个对象,这样有两个优点:
- 节约内存,新建100个值为1的Integer也就只占用一个存储空间
- 速度快,每次新建Integer对象都需要花费时间,对常用值的对象就不需要花时间来new对象了
那么,哪些范围内的数值会被缓存呢?javadoc的描述中说默认是-128 到 127。
能从jdk源码中找到缓存相关的这块代码吗?笔者在参考3中找到了,简化加注释如下:
private static class IntegerCache
static final int low = -128;#最小值默认是-128,这个不能改
static final int high;
static final Integer[] cache;
static
// 最高值默认为127,但也可以修改
int h = 127;
high = h;
int size = (high - low) + 1;
// 新建一个Integer数组,初始值为-128, -127, ..., 0, 1, 2, ..., 127
if (archivedCache == null || size > archivedCache.length)
Integer[] c = new Integer[size];
int j = low;// low=-128
for(int i = 0; i < c.length; i++)
c[i] = new Integer(j++);// -128, -127, ..., 0, 1, 2, ...high
archivedCache = c;
cache = archivedCache;//cache作为最终缓存数组
# valueOf()的定义,auto-boxing会调用
public static Integer valueOf(int i)
if (i >= IntegerCache.low && i <= IntegerCache.high) //low,high的默认值见上面class中的定义
return IntegerCache.cache[i + (-IntegerCache.low)];//不new object,而是直接从cache中读出object返回
return new Integer(i);//不在if的区间内,就new object 返回
3. 注意
从上面的JDK源码分析来看,我们知道:
-
Java的Integer的缓存机制必须在auto-boxing模式下,或者主动调用valueOf(),才会被使用(auto-boxing才会调用valueOf())。
非auto-boxing模式下,如果不主动调用valueOf(),比如new Integer是绝对不会触发这个缓存机制的。 -
new对象而不是用auto-boxing机制,是不会调用缓存的,比如
Integer a1 = 9;
Integer b1 = 9;
System.out.println(a1==b1);//true
Integer a2 = new Integer(9);
Integer b2 = new Integer(9);
System.out.println(a2==b2);//false
- 如果默认大于127,就不会调用缓存,比如
Integer a3 = 127;//auto-boxing
Integer b3 = 127;//auto-boxing
System.out.println(a3==b3);//true
Integer x = 128;//auto-boxing
Integer y = 128;//auto-boxing
System.out.println(x==y);//false, 因为上界值默认为127(等于127),大于这个值就不会调用cache,而是真实的new对象了
- 上界阈值默认为127,但可以通过修改虚拟机参数来改变上限值
具体如何修改呢,比如如下代码保存到Test.java
中
Integer x = 128;//auto-boxing
Integer y = 128;//auto-boxing
System.out.println(x==y);
编译命令:javac Test.java
运行命令:java -XX:AutoBoxCacheMax=200 Test
如果加上 -XX:AutoBoxCacheMax=200
参数来运行程序,表示可以将Integer的缓存上界值(在auto-boxing模式下)改变为200(默认为127),这样程序输出就是true。
如果不加这个参数,就和上一题一样,输出false。
参考
- https://www.geeksforgeeks.org/java-integer-cache/
- https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html
- https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Integer.java#L1071
- https://stackoverflow.com/questions/31445024/does-autoboxing-call-valueof
以上是关于从JDK源码理解Java Integer的缓存机制的主要内容,如果未能解决你的问题,请参考以下文章