“compile->compile” rather than “compile-interpret”. More specifically,
1) Compile time — java source code is first compiled (by javac) to platform-independent byte code. You can move this *.class files to any machine of any arch. However, by definition, platform-independent code is not optimized for any platform.
2) Run time – byte code is compiled to platform-specific machine code “just in time”. The machine code is similar to those produced by gcc.
This is rather essential knowledge. I think sometimes quizzed on interviews.
O’Reilly [[java performance]] P75 has concise introduction of Hot-Spot JIT. The JIT only compiles the most critical “hotspots”, not those parts of the byte code executed once only. Therefore, the JIT needs some warm-up time, during which it collects statistic about each code chunk, while executing the half-cooked byte code from Phase 1. Based on the statistics it makes heuristic optimizations, as illustrated on P76.
Note it’s possible to execute the byte code from Phase 1 without second-phase compilation. This is actually optimal when the methods are executed only once — interpreting is faster for them!
This description is consistent with Ab-Initio architect who said in 2012 (not in his original words) that java system needed to consume some input data during warm-up, before throughput became comparable to c++.