除了缓存指令,解释器生成的本机代码和 JIT 之间有什么区别吗?

Besides caching instructions, is there any difference between the native code generated by an interpreter and JIT?

我不明白解释器和 JIT 之间的区别。例如,来自 this answer:

JVM is Java Virtual Machine -- Runs/ Interprets/ translates Bytecode into Native Machine Code

JIT is Just In Time Compiler -- Compiles the given bytecode instruction sequence to machine code at runtime before executing it natively. It's main purpose is to do heavy optimizations in performance.

两者都生成本机机器代码。然后,从 this other answer:

An interpreter generates and executes machine code instructions on the fly for each instruction, regardless of whether it has previously been executed. A JIT caches the instructions that have been previously interpreted to machine code, and reuses those native machine code instructions.

在我看来,解释器类似于 JIT,因为它也将字节码翻译成本机代码,不同之处在于 JIT 执行一些优化,如缓存。

这样对吗?还有其他主要区别吗?

我认为以上定义不一定正确。

"mandatory" 或 "necessary" 不是 解释器 翻译成机器代码。

本质上,口译员解释。它找到一个循环,然后 "runs" 该循环。这与创建执行循环的机器代码相同。

这条语句:

An interpreter generates and executes machine code instructions

为假。

简而言之,解释器是一种循环遍历程序指令(无论是来自虚拟指令集还是真实指令集)并一条一条执行的程序。这是通过编程出每条指令应该做什么并在解释器中模拟它来完成的。

在最简单的层面上,您可以想象一个解释器通常看起来像这样:

for(byte byteCode : program) {
    if(byteCode == ADD_BYTECODE) {
        add();
    }
    // ... others
}

这与 CPU 执行机器代码的概念并没有太大区别,但在 CPU 的情况下,大部分逻辑直接在硬件中实现。

我想你可以说解释器是一个在软件中模拟CPU的程序。


JIT 编译器完成运行将字节码转换为机器码并在此过程中对其进行优化的工作。机器代码相对于字节代码的理论优势之一是,例如,特定的 CPU 可能有可用的专用指令,运行 比等效的字节代码更快。

在 JVM 的情况下,这是在方法 "hot" 时完成的,即当它 运行 很多时。然而,JIT 编译需要很长时间(尝试 运行ning 带有 -XX:-TieredCompilation -Xcomp 标志的 Java 程序,默认强制 C2 编译,你会看到启动时间的差异),所以先解释字节码会更快。这也提供了收集分析数据的机会,这些数据是关于程序如何 运行ning 的数据(例如 if b运行ch 被触发了多少次,或者哪些类型用于动态调度调用).在 JIT 编译期间也使用分析数据来进行更好的优化。