Clarification regarding traditional interpreter, compiler and JIT compiler/interpreter

前提是你 提交于 2019-11-30 22:39:04
Smallhacker

Disclaimer: Take all of this with a grain of salt; it's pretty oversimplified.

1: You are correct in that the computer itself doesn't understand the code, which is why the JVM itself is needed. Let's pretend XY means "add the top two elements on the stack and push the result". The JVM would then be implemented something like this:

for(byte bytecode : codeToExecute) {
    if (bytecode == XX) {
        // ...do stuff...
    } else if (bytecode == XY) {
        int a = pop();
        int b = pop();
        push(a+b);
    } else if (bytecode == XZ) {
        // ...do stuff...
    } // ... and so on for each possible instruction ...
}

The JVM has, in the computer's native machine code, implemented each individual instruction and essentially looks up each chunk of bytecode for how to execute it. By JITting the code, you can achieve large speedups by omitting this interpretation (i.e. looking up how each and every instruction is supposed to be handled). That, and optimization.

2: The JIT doesn't really run the code; everything is still run inside the JVM. Basically, the JIT translates a chunk of bytecode into machine code when appropriate. When the JVM then comes across it, it thinks "Oh hey, this is already machine code! Sweet, now I won't have to carefully check each and every byte of this as the CPU understands it on its own! I'll just pump it through and everything will magically work on its own!".

3: Yes, it is possible to pre-compile code in that way to avoid the early overhead of interpretation and JITting. However, by doing so, you lose something very valuable. You see, when the JVM interprets the code, it also keeps statistics about everything. When it then JITs the code, it knows how often different parts are used, allowing it to optimize it where it matters, making the common stuff faster at the expense of the rare stuff, yielding an overall performance gain.

  1. At the end, even in an interpreter the machine code that is equivalent to a bytecode instruction gets run, it just happens more indirectly. Think of it like a piano. A CPU is like a player piano. A compiler punches holes into a strip of paper, which you then run on the piano. Using an interpreter is essentially placing a human-like machine in front of the piano who reads the sheet-music and pushes the keys on the piano. In the end, the same chords sound out, but there's an additional level of indirection.

  2. Yes. Pretty much.

  3. As you mention, Java was touted as "compile once, run anywhere". So the bytecode is an important feature to deliver that promise. The reason why it doesn't get compiled when it arrives on your computer is a practical one: Compiling is slow. Usually, it happens at the software developer's. If every Java application you launch was compiled the first time, you would be waiting a while.

    Since most programs do not get run completely (there are branches that aren't taken, menu items you never choose etc.), it is usually faster to compile the parts that are needed, as they are needed. It also saves on disk space, as otherwise you'd have two copies of every program on your computer.

That said, you're not the first one to wonder about this, and in fact some people write their programs in Java, but use a compiler to actually generate executables from them. Java(-to-native) compilers exist, they're just not the common use case, because many people at that point use portable C or C++.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!