Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different behavior running and debugging the program Java, Eclipse

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.

like image 220
cliffroot Avatar asked Jan 15 '16 17:01

cliffroot


People also ask

What is the difference between debug and run in Eclipse?

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.

How do you debug and run in Eclipse?

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.

How can you debug a program while it's being used in Java?

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.


2 Answers

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.

like image 106
user3009344 Avatar answered Oct 23 '22 09:10

user3009344


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.

like image 31
David Pérez Cabrera Avatar answered Oct 23 '22 07:10

David Pérez Cabrera