I have this code (put aside its appropriateness for now):
Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache");
Field cacheField = cacheClass.getDeclaredField("cache");
cacheField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL);
Integer betterCache[] = new Integer[255];
for (int i = 0; i < betterCache.length; i++) {
betterCache[i] = 20;
}
cacheField.set(null, betterCache);
System.out.println(10);
System.out.println((Integer) 10);
I expect the second println
to print 20, as I replaced cached Integers
with 20. When I debug program in Eclipse it does as I expect, it gets the value from the cache and prints 20, whereas it prints 10 in both cases when I just run it either from IDE or by invoking java
. How can this behavior be explained?
UPD: It works this way if compiled with 1.8 javac. It prints 10 and 20 if compiled with 1.6 version.
When you're debugging, Eclipse will stop at breakpoints and allow other debugging actions (view running threads, etc.). When you run, it won't. If you start by selecting "Run", you can later attach the debugger through the Device view. That will switch to "Debug" mode.
Starting the Debugger. To debug your application, select a Java file with a main method. Right-click on it and select Debug As Java Application. If you started an application once via the context menu, you can use the created launch configuration again via the Debug button in the Eclipse toolbar.
Most debuggers allow you to debug a program in one of 2 ways: You run the program from within the debugger. You attach debugger to an already running program.
This is definitely caused by Just in Time Compiler. You should add -XX:+PrintCompilation to JVM options, it is also more visible if you iterate
System.out.println((Integer) 10);
a lot of times. You will notice that compiling
java.lang.Integer::valueOf (32 bytes)
and
java.nio.ByteBuffer::arrayOffset (35 bytes)
affects the result.
EDIT
I was completely wrong
Definitely you are playing with fire, in my point of view, this is for a race conditions (unsafe thread in java 8). If you check this:
Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache");
Field cacheField = cacheClass.getDeclaredField("cache");
cacheField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL);
Integer firstCache[] = (Integer[])cacheField.get(null);
Integer betterCache[] = new Integer[255];
for (int i = 0; i < betterCache.length; i++) {
betterCache[i] = 20;
}
System.out.println(firstCache == betterCache);
cacheField.set(null, betterCache);
System.out.println(10);
for (int i = 0; i < 1000000; i++) {
System.out.println((Integer) 10);
}
You'll see the Java burn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With