5

What sort of optimizations would Java Runtime perform on the follow snippet of code? The bytecode doesn't reveal any optimization however I feel that Java should take the last value of the for loop without running the entire for loop since String is a rudimentary Java class.

NOTE. this question was asked on a class test; however, I couldn't provide enough evidence to back my claim.

public class Main {

    public static void main(String[] args) {
        String str = null;
        for (long i = 0; i < 10000000000L; i++) {
            str = new String("T");
        }

        System.out.println(str);
    }
}
7
  • 4
    Essentially no optimization is performed at the bytecode level; it's almost all at runtime. The JIT is mostly a magic black box that you can't make any guarantees about, but it's not out of the realm of possibility that the whole loop could get eliminated. Commented Dec 1, 2015 at 19:47
  • You can have a peek at how the JIT "handles" your code using the following options to the JVM: -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining. Commented Dec 1, 2015 at 19:50
  • @fge Deciphering that output is quite a challenge. I am not entirely sure what is going on there. Commented Dec 1, 2015 at 20:07
  • "would" is a weird question. "could" might be interesting. Commented Dec 1, 2015 at 20:37
  • 1
    It's a poor question to ask in a test, as it isn't specified anywhere, and it is rather difficult to discover as well. And vendor- and version-dependent.There could be zero optimisation, or elimination of the loop. The fact that 'String is a "rudimentary" Java class' doesn't really have anything to do with it in this case. Commented Dec 1, 2015 at 21:54

1 Answer 1

1

While I can't speak to exactly what the jit compiler is doing, the optimization you are asking it to do (to determine that it is safe to skip the loop body entirely) is actually extremely difficult to do, and so I highly doubt it it is done. This is true regardless of String being a "rudimentary Java class".

To understand better, first let's assume that instead of String, we are creating instances of an arbitrary class Foo. It would only be safe to skip the creation of all those Foo objects if we knew two things: that calling new Foo() didn't have any observable side effects; and that no references to Foo "escaped" the loop body.

An observable side effect would be something like setting the value of a static member (e.g. if the Foo class kept a static count of all the times Foo() had been called). An example of a reference escaping would be if the this variable inside of Foo() was passed somewhere else.

Note that it isn't enough to just look at Foo(), you need to look at Foo's superclass' constructor (and all the way up the chain to Object). And then you need to look at all the code that gets executed upon initialization of each of those objects. And then look at all the code that gets called by that code. That would be a tremendous amount of analysis to do "just-in-time".

public class Foo extends Bazz{
    static int count = 0;

    public Foo(){
        // Implicit call to Bazz() has side effect
        count++; // side effect
        Bazz.onNewFoo(this); // reference escaping
    }

    Bazz bazz = new Bazz();  // side effect
    {
        Bazz.onNewBazz(this.bazz); // reference escaping
    }
}

class Bazz{
    static int count = 0;

    static List<Foo> fooList = new LinkedList<>();
    static List<Bazz> bazzList = new LinkedList<>();

    static void onNewFoo(Foo foo){
        fooList.add(foo);
    }

    static void onNewBazz(Bazz bazz){
        bazzList.add(bazz);
    }

    public Bazz(){
        count++;
    }
}

You might think we should just let javac do this analysis and optimization for us. The problem with that is, that there is no way to guarantee that the version of Foo() that was on the classpath at compile-time will be the same as that which is on the classpath at run-time. (Which is a very valuable feature of Java - it allows me to move my application from Glassfish to Tomcat without recompiling). So we can't trust analysis done at compile-time.

Finally, realize that String is no different from Foo. We'd still need to run that analysis, and there is no way to do that analysis in advance (which I why I can upgrade my JRE without recompiling my apps)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.