Let’s talk about Java Integer cache pool IntegerCache
directory
- Start with a classic case
- IntegerCache introduction
- Bytecode verification
- conclusion
- extension
- Expand the conclusion
- Written in the end
This article from the shallow to the deep, the difficulty of the whole is not high, may be some positions for some students are blind.
If you are in a hurry, you can jump to the conclusion to see the conclusion.
Bytecode verification and extension may be difficult for beginners to read, so you can record them and wait for some time to learn them in the future.
Introducing classic cases
Let’s start with a classic example
public class IntegerCacheExample { public static void main(String[] args) { Integer a = 127; Integer b = 127; System.out.printf("a==b: %s.\n", a == b); Integer c = 128; Integer d = 128; System.out.printf("c==d: %s.\n", c == d); }}Copy the code
Very simple two outputs, think about it for five seconds and then open and fold and see the answer.
Fold: Click to see the answer
a==b: true.
c==d: false.
I don’t know if the answer is the same as you think, but let’s talk about why.
Integer Specifies the cache pool IntegerCache
Integer cache pool? Is it something like a string cache pool?
The only similarity is that the pool does store some values.
IntegerCache, let’s go to java.lang.Integer source code to find out.
Jdk1.8.0-OpenJDK
IntegerCache is an internal class in line 780, so I’m going to look at the comment first.
Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS.
The cache is initialized on first usage. The size of the cache may be controlled by the -XX:AutoBoxCacheMax=<size> option. During VM initialization,
java.lang.Integer.IntegerCache.high property may be set and saved in the private system properties in the sun.misc.VM class.
private static class IntegerCache {
Copy the code
Google Translate explains:
Object identity semantics cached to support auto-boxed values between -128 and 127 (inclusive) as required by JLS. The cache is initialized the first time it is used. The size of the cache can be controlled by the -xx :AutoBoxCacheMax=<size> option. In the process of VM initialization, Java. Lang. Integer. IntegerCache. High attribute may be set up and stored in the sun. The misc. VM class in the system of private property.Copy the code
Key words:
- – 128 ~ 127
- The size can be adjusted by ** -xx :AutoBoxCacheMax**
The cache generation ranges from -128 to 127, and the parameters can be modified by configuring the JVM parameter AutoBoxCacheMax before starting.
So we know why a==b is true and c==d is false, because both a and B are taken from the cache pool and point to the same pointer, while C and D are not taken from the cache pool and point to their respective memory addresses. (If you don’t understand what a new object refers to a new memory address, you can refer to the blog memory post. If you can’t find it, you may not have finished writing it and have not published it yet.)
Let’s try to see if this is true
IntegerCache bytecode authentication– This section is difficult for beginners to read. It can be easily read. There is no need to study deeply
Look at the pointer address first. Run the following code
The system.identityHashCode (Object x) method can return the memory address of an Object, regardless of whether the Object’s class overrides the hashCode() method.
System.out.printf("a:%s.\n", System.identityHashCode(a));
System.out.printf("b:%s.\n", System.identityHashCode(b));
System.out.printf("c:%s.\n", System.identityHashCode(c));
System.out.printf("d:%s.\n", System.identityHashCode(d));
Copy the code
The output is as follows:
a:1118140819.
b:1118140819.
c:1975012498.
d:1808253012.
Copy the code
You can see that a and B point to the same address, and c and D point to different addresses. Let’s take a look at how the JVM does this from a bytecode perspective.
To reduce bytecode complexity, I commented out the comparison section of the code
public class IntegerCacheExample { public static void main(String[] args) { Integer a = 127; Integer b = 127; // System.out.printf("a==b: %s.\n", a == b); Integer c = 128; Integer d = 128; // System.out.printf("c==d: %s.\n", c == d); }}Copy the code
Generating bytecode and executing the command in command line mode in the directory of the main method produces a.class file with the same name
javac IntegerCacheExample.java
Copy the code
View bytecode
javap -c IntegerCacheExample.class
Copy the code
The bytecode is as follows:
Compiled from "IntegerCacheExample.java"
public class com.xh.basic.lang.integer.IntegerCacheExample {
public com.xh.basic.lang.integer.IntegerCacheExample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 127
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush 127
8: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: astore_2
12: sipush 128
15: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: astore_3
19: sipush 128
22: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
25: astore 4
27: return
}
Copy the code
Don’t worry if you don’t understand. I’m not omnipotent. Let’s find some key positions to interpret.
Public static void main public static void main public static void main
We see it in lines 2, 8, 15, and 22 under Main
// Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer
Copy the code
As you can guess, JAVA makes the following optimizations at runtime
Integer x = num; X = integer.valueof (num);Copy the code
We follow the source code into the integr. valueOf method
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Copy the code
The source code tells us that when valueOf is executed, it checks whether I is in the range [low, high]. If it is in the range, it is taken from IntegerCache. If it is not in the range, new Integer(I) is performed, so we can conclude.
conclusion
When Integer x = num is initialized, if num is in the range from -128 to 127 (the default range), the value will be retrieved from IntegerCache and will point to the same pointer address. If num is outside the range, new Integer will point to a different pointer.
extension
We see that the IntegerCache comment says -xx :AutoBoxCacheMax, so we can try it out and see if it works and what happens when we change it.
We add -xx to the JVM run parameter :AutoBoxCacheMax=200
I used IDEA, and some IDEA did not have this VM options, so we selected the interface position one by one
Run –> Eidt Configurations –> Modify options –> Add VM options
Once added, you can see it in the interface location, and you can add the running parameters
Run the code after Apply to see the effect
AutoBoxCacheMax=200
sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”);
This method gets the value of AutoBoxCacheMax in the VM parameter
public class IntegerCacheExample { public static void main(String[] args) { System.out.printf("high:%s.\n", sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high")); Integer a = 127; Integer b = 127; System.out.printf("a==b: %s.\n", a == b); Integer c = 128; Integer d = 128; System.out.printf("c==d: %s.\n", c == d); Integer e = 200; Integer f = 200; System.out.printf("e==f: %s.\n", e == f); Integer g = 201; Integer h = 201; System.out.printf("g==h: %s.\n", g == h); System.out.printf("a:%s.\n", System.identityHashCode(a)); System.out.printf("b:%s.\n", System.identityHashCode(b)); System.out.printf("c:%s.\n", System.identityHashCode(c)); System.out.printf("d:%s.\n", System.identityHashCode(d)); System.out.printf("e:%s.\n", System.identityHashCode(e)); System.out.printf("f:%s.\n", System.identityHashCode(f)); System.out.printf("g:%s.\n", System.identityHashCode(g)); System.out.printf("h:%s.\n", System.identityHashCode(h)); }}Copy the code
The output is as follows:
high:200.
a==b: true.
c==d: true.
e==f: true.
g==h: false.
a:1118140819.
b:1118140819.
c:1975012498.
d:1975012498.
e:1808253012.
f:1808253012.
g:589431969.
h:1252169911.
Copy the code
You can see that 200 is taken from IntegerCache and 201 is a new Integer for a different pointer. Configuration to take effect
AutoBoxCacheMax=126
If it’s less than 127, is it valid? Let’s test that out.
public class IntegerCacheExampleMinValue { public static void main(String[] args) { System.out.printf("high:%s.\n", sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high")); Integer a = 127; Integer b = 127; System.out.printf("a==b: %s.\n", a == b); Integer c = 128; Integer d = 128; System.out.printf("c==d: %s.\n", c == d); Integer min126a = 126; Integer min126b = 126; System.out.printf("min126a==min126b: %s.\n", min126a == min126b); System.out.printf("a:%s.\n", System.identityHashCode(a)); System.out.printf("b:%s.\n", System.identityHashCode(b)); System.out.printf("c:%s.\n", System.identityHashCode(c)); System.out.printf("d:%s.\n", System.identityHashCode(d)); System.out.printf("min126a:%s.\n", System.identityHashCode(min126a)); System.out.printf("min126b:%s.\n", System.identityHashCode(min126b)); }}Copy the code
The output is as follows:
high:126.
a==b: true.
c==d: false.
min126a==min126b: true.
a:697960108.
b:697960108.
c:943010986.
d:1807837413.
min126a:2066940133.
min126b:2066940133.
Copy the code
Min126a ==min126b is ok, but why is a==b? The cache pool high is 126. So 127 should be new? Did the configuration not work? It’s still 127?
By printing the value of high, we found that the configuration did take effect, but it did not take effect because the source code made a judgment. Specify a method for assigning the maximum value of the cache pool in IntegerCache.
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue ! = null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } }Copy the code
The key code
i = Math.max(i, 127);
Copy the code
As you can see, it takes the vm parameter AutoBoxCacheMax and 127 and takes the maximum value, that is, if we set the AutoBoxCacheMax parameter to less than 127, it won’t take effect.
If you don’t understand, please leave a message to me at the end of this article. I will reply one by one.
Expand the conclusion
-xx :AutoBoxCacheMax You can change the maximum range of the cache pool. The value must be greater than 127 to take effect. If the value is smaller than or equal to 127, the default value 127 is still used.
Written in the end
I am dahui, a program ape who is still working hard. I hope you and I can continue to learn and grow in the future.
And don’t lose your joy. Be a happy programmer.
I hope this article can bring you some benefits.