I've got a simple class for the illustration purposes:
public class Test {
public int test1() {
int result = 100;
result = 200;
return result;
}
public int test2() {
return 200;
}
}
The bytecode produced by the compiler (inspected by javap -c Test.class
) is the following:
public int test1();
Code:
0: bipush 100
2: istore_1
3: sipush 200
6: istore_1
7: iload_1
8: ireturn
public int test2();
Code:
0: sipush 200
3: ireturn
Why is the compiler not optimizing the test1
method to the same bytecode produced for the test2
method? I would expect it to at least avoid redundant initialization of the result
variable considering that it is easy to conclude that the value 100
is not used at all.
I observed this with both Eclipse compiler and javac
.
javac
version: 1.8.0_72
, installed as part of JDK together with Java:
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
The JVMs JIT compiler is one of the fascinating mechanisms on the Java platform. It optimizes your code for performance, without giving away its readability. Not only that, beyond the “static” optimization methods of inlining, it also makes decisions based on the way that the code performs in practice.
In computing, an optimizing compiler is a compiler that tries to minimize or maximize some attributes of an executable computer program. Common requirements are to minimize a program's execution time, memory footprint, storage size, and power consumption (the last three being popular for portable computers).
JIT compiler monitors the java program and compiles the bytecode of hot methods (i.e. methods that get called frequently) into machine specific code (i.e. platform binary or native code). This compilation of bytecode into native code occurs as the program executes.
The server compiler is selected by default on the server-class machines. Tiered compilation, introduced in Java SE 7, brings client startup speeds to the server VM. A server VM uses the interpreter to collect profiling information about methods that is fed into the compiler.
JVM optimizes the bytecode, creating something called a code cache. Unlike C++, JVM can collect a lot of data about your program, eg, How hot is that for loop?, Is that code block even worth optimizing?, etc. So optimizing here is very useful, and an often produce better results.
If you optimize when translating from java to bytecode (ie, when you call javac), your code might be optimal for your computer, but not for some different platform. So it makes no sense to optimize here.
As an example, suppose your program uses AES encryption. Modern CPUs have AES-specific instruction sets, with special hardware to make the encryption go a lot faster.
If javac attempts to optimize at compile time, then it will either
If instead javac leaves them as is in the byptcode, then the JVM running on newer CPUs can recognize them as AES and exploit this CPU capability, while JVMs running on older CPUs can optimize them at a software level at runtime (code cache), giving you both optimality and compatibility.
A typical Java virtual machine optimizes your program at runtime, not during compilation. At runtime, the JVM knows a lot more about your application, both about the actual behavior of your program and about the actual hardware your program is executed upon.
The byte code is merely a description of how your program is supposed to behave. The runtime is free to apply any optimization to your byte code.
Of course, one can argue that such trivial optimizations could be applied even during compilation but in general it makes sense to not distribute optimizations over several steps. Any optimization is effectively causing a loos of information about the original program and this might make other optimizations impossible. This said, not all "best optimizations" are always obvious. An easy approach to this is to simply drop (almost) all optimizations during compilation and to apply them at runtime instead.
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