Execution speed - predefinition

hey, you bytecode native speakers :slight_smile:

Can you tell me, if the following two code fragments produce different byte code and especially execute in different performance?

code1


MyClass c = null;

for ( int i = 0; i < myList1.size(); i++ )
{
    c = myList1.get( i );
    
    c.doSomething();
}

for ( int i = 0; i < myList2.size(); i++ )
{
    c = myList2.get( i );
    
    c.doSomething();
}

code2


for ( int i = 0; i < myList1.size(); i++ )
{
    MyClass c = myList1.get( i );
    
    c.doSomething();
}

for ( int i = 0; i < myList2.size(); i++ )
{
    MyClass c = myList2.get( i );
    
    c.doSomething();
}

I do like the second variant better. But is it slower because of the in-place declaration of the variable c inside of the loops? I would expact modern compilers to eliminate a possible disadvantage. But I don’t know for sure.

Marvin

Shouldn’t be any difference when it gets run. Though you should manually hoist the call to size() outside of the loop, if you know size() isn’t going to change.

Cas :slight_smile:

I’d go with the second variant too as its likely to be picked up by Escape Analysis for better optimisation.

Thanks guys.

How can I read the byte code to make it sure? When I open a .class file, there’s just a lot of binary noise with only a few class names here and there.

Yes, sure.

Marvin

I’ve seen the second option be executed faster, but that was a long time ago, and the amount of difference depended on which JVM you were running it on so things might have changed.
The speed difference aside, I think the 2nd option is also slightly nicer as the MyClass doesn’t need to be outside of the loop (so then you can make it final, which makes your code less error-prone).

As princec noted, size() is being executed at every iteration so you might want to do something about that too, like counting down to 0 if possible instead of counting up to size() - remember checking against 0 can be faster than checking against x.

There are really low-level optimization considerations though (they might not make any difference whatsoever if this code is not some inner loop that takes 50% or more of execution time).

No, this is not a critical part of my code. I just ask, because I love to optimize my code to the last quantum. So I just wanted to know, because some people do the (IMHO) old school way (code1) and I don’t like it ;). Well sometime old school is still good. But not this time, if it is not faster.

Of course I know about the size() inside the loop. I would always push it outside, if it is important. I didn’t know, there is a difference between checking against 0 vs. x, though. So thank you very much.

What about the byte code? Can I read it somehow like an assembler code listing?

Marvin

The thing is, the byte code doesn’t make a lot of difference, what counts is what Hotspot compiles the bytecode into, and it puts quite a lot of effort into optimising that compilation.

Style-wise I prefer the second code, as it doesn’t leave a dangling reference at the end to what is basically a temporary variable which has no semantic meaning outside of the loops.

Escape analysis will be the same in either case: nothing escapes the whole block. But no normal JRE currently does anything with EA and stack allocation yet.

Your best bet is to benchmark the code. Even a microbenchmark will probably show you what you want to see, even though it’s probably not a very useful measurement…

Cas :slight_smile:

ok, thanks.

Marvin

Check the javap executable in JDK_HOME/bin

Just from a purely analytical perspective code fragment 1 will contain an additional assignment to null.
Beyond that the generated bytecode will be identical.