Native machine language
Just-in-time compilation translates Java bytecode into native machine language during program execution.
A Common Assumption About Java Speed
A common early assumption about Java was simple. If a program is written as bytecode and an interpreter executes that bytecode, the program can never be as fast as a program already compiled into the computer's native machine language. The assumption identifies a real performance concern, but it leaves out an important part of how Java execution can work. This article follows one program's execution step by step to show where the assumption breaks down.
Just-in-time compilation translates Java bytecode into native machine language during program execution.
Tracing Direct Interpretation
Start with the simplest case. A Java program is available as bytecode, and an interpreter executes that bytecode directly. For each bytecode instruction the interpreter reaches, it carries out the work that instruction describes. The program is never translated into native machine language, so every execution of a given part of the program goes through the interpreter again.
The comparison shows the key difference. Direct interpretation has one stage per instruction: the interpreter works through the bytecode as it is reached. Just-in-time compilation adds a translation stage. The bytecode part is translated into native machine language, and the translated result is what runs in later executions of that part. The translation itself happens while the program is running.
What Just-in-Time Compilation Adds
An interpreter alone only executes bytecode directly. Just-in-time compilation goes further: it also translates parts of the program. Those translated parts can execute more quickly than interpreted bytecode. The sequence below shows where native machine language fits in the flow from bytecode to running program.
Following One Code Region Across Repeated Runs
The benefit of just-in-time compilation comes from repetition. A given part of a program is often executed many times as the program runs. If that part is translated into native machine language during execution, later executions of the translated part can be faster than repeatedly interpreting it. Consider one region of code that a program runs ten times. The first run includes the translation cost. The later runs use the translated result.
Tracking one region over several executions
A program part is executed repeatedly. The learner asks how the one-time translation cost is repaid as the part keeps running. The numbers below are illustrative, chosen only to show the pattern, and are not measurements of any real JVM.
- 1Run 1
The part is reached for the first time. The translation into native machine language happens during this run, so the first run carries the translation cost.
- 2Run 2
The translated native machine language is used. The part no longer has to be interpreted again, so this run can be faster than interpreting the bytecode would be.
- 3Runs 3 to 10
Each later run reuses the translated result. The translation cost is spread across all the runs, so its effect on the total time shrinks as the count grows.
- 4Total time
Total time is the translation cost plus the cost of all runs. When the part runs many times, the savings on each later run can outweigh the one-time translation cost.
The benefit depends on repetition. A part that runs once gains little from translation. A part that runs many times can gain a great deal, which is why the greatest benefit occurs when a program part is executed many times.
The diagram shows the pattern. The translation cost appears once, at the first run. Every later run reuses the translated result. As the number of runs grows, the one-time cost matters less compared with the savings on each later run. This is why translation pays off most for code that is executed many times.
Mistakes About Bytecode Speed
Common mistake Assuming any bytecode program must always run slower than a native machine language program
Why it failsThe source states that interpreted bytecode can run slower than native machine language, but just-in-time compilation can translate parts of the bytecode into native machine language during execution. Those translated parts can then execute much more quickly than they could through interpretation.
Do this insteadState the claim precisely: interpreted bytecode can be slower, but parts translated by just-in-time compilation can run faster, and the overall execution time can improve significantly.
Common mistake Believing translation helps every part of a program equally
Why it failsThe benefit comes from repetition. A part executed many times can benefit greatly, while a part executed only once gains little from being translated.
Do this insteadThink about how often a given part runs before deciding how much translation can help.
Common mistake Thinking just-in-time compilation replaces bytecode entirely
Why it failsThe program still runs from bytecode. The translation adds native machine language for selected parts while the program executes.
Do this insteadDescribe just-in-time compilation as translating parts of the bytecode during execution, not as discarding the bytecode.
Predicting Where Translation Pays Off
What do you think happens?
A part of a program runs exactly once during the whole execution. Does just-in-time compilation give that part a large benefit from translation?
Reveal answer
No, because the greatest benefit occurs when a program part is executed many times.
The benefit of just-in-time compilation comes from repetition. A part that runs once pays the translation cost without getting many later runs that use the translated result, so it gains little.
Explain in your own words why the claim that all bytecode programs are always slower than native programs is incomplete. Your explanation should mention interpretation, translation during execution, and repeated execution.
Hints
- Start with what an interpreter alone does to bytecode.
- Think about what happens to a part of the program on its later executions after translation.
- Ask how the number of executions changes the balance between translation cost and savings.
Key Takeaways
- Just-in-time compilation translates Java bytecode into native machine language during program execution, going beyond direct interpretation.
- Direct interpretation executes each bytecode instruction through the interpreter every time it is reached, while just-in-time compilation translates parts of the program so later executions use native machine language.
- The benefit comes from repetition: a part executed many times can run much faster after translation, which can significantly improve overall execution time.
- Interpreted bytecode can be slower than native machine language, but the claim that bytecode programs must always be slower is a misconception.