【问题标题】:Clarifications on JIT Compiler and Interpreter关于 JIT 编译器和解释器的说明
【发布时间】:2014-06-18 11:50:20
【问题描述】:

我对 JIT 编译器和解释器有一些疑问。 从他们的定义开始:

(翻译)来自维基百科:

在计算机科学中,解释器是直接执行(即执行)以编程或脚本语言编写的指令的计算机程序,而无需事先将它们批量编译成机器语言。解释器通常使用以下策略之一来执行程序:
1) 解析源代码并直接执行其行为
2) 将源代码翻译成一些有效的中间表示并立即执行此
3) 显式执行由编译器生成的存储预编译代码[1],该编译器是解释器系统的一部分

(JIT 编译器) 来自维基百科:

在计算中,即时编译 (JIT) 也称为动态翻译,是在程序执行期间(在运行时)而不是在执行之前完成的编译。[1]大多数情况下,这包括翻译成机器代码,然后直接执行,但也可以指翻译成另一种格式。

来自 StackOverFlow:

即时编译是在执行之前将非本地代码(例如字节码)转换为本地代码。

我有 4 个问题:
1) 总是说 JIT=runtime,为什么解释器不能在运行时工作?在程序运行时,解释器不是在运行时翻译和执行每一行吗?
2) 总是说 JIT 将非本地代码转换为本地代码,那又如何呢?解释器不会将代码转换为本机代码吗?如果未将指令翻译为本机代码,我的进程如何执行指令?所以解释器也需要将代码翻译成本机代码。
3) 普通解释器在需要执行时翻译每一行,而使用 JIT 编译器时,每一行在执行之前就翻译,因此在需要执行该行的那一刻是可用的。不是吗?
4) 那么解释器和 JIT 编译器之间的真正区别是什么,它们都在运行时执行程序,都从中间语言翻译为本机代码...

【问题讨论】:

    标签: java interpreter jit


    【解决方案1】:

    解释器不会将源代码翻译成本地机器代码。虽然您的计算机只能执行机器代码,但它执行的机器代码不一定必须是高级语言的翻译。令人困惑?让我们看一个简单的玩具示例...

    考虑编程语言 PrintForPony 有两个函数,print 和 sleep。 print 函数将一个字符串作为其唯一参数并将其打印到标准输出,而sleep 将一个正整数作为其唯一参数并使当前线程在该时间段内休眠。 PFP 的伪 BNF:

    program        ::= statement_list
    statement_list ::= statement | statement NEWLINE statement_list
    statement      ::= print STRING | sleep POSITIVE_INTEGER
    

    这是 PFP 解释器的一个超级简单的 Java 实现。该程序将源文件作为其唯一参数并对其进行解释:

    import java.io.BufferedReader;
    import java.io.FileReader;
    
    public class PFPInterpreter {
        public static void main(String[] args) throws Exception {
            BufferedReader br = new BufferedReader(new FileReader(args[0]));
            String line = null;
            while ((line = br.readLine()) != null) {
                if (line.startsWith("print ")) {
                    System.out.println(line.substring("print ".length()));
                } else if (line.startsWith("sleep ")) {
                    Thread.sleep(Long.parseLong(line.substring("sleep ".length())));
                } else {
                    throw new IllegalArgumentException("Unknown function: " + line);
                }
            }
        }
    }
    

    一个示例源文件:

    print Hello, World!
    sleep 1000
    print Goodbye, World!
    

    以及样本输出:

    $ java PFPInterpreter test.pfp 
    Hello, World!
    Goodbye, World!
    

    PFP 在任何时候都不会被翻译成本地机器代码。执行的本机机器代码是 JVM,它与这种玩具语言无关。我们还可以为 PFP 编写一个编译器,将代码转换为可执行文件(我不打算这样做,因为这个答案已经太长了),但问题的关键在于解释器不会编译为本机机器代码 - 它读取输入文件并根据内容做一些事情。

    回答问题:

    1) 解释器是为您运行代码的运行时。我不确定你在哪里读到解释器在运行时不起作用,但我也不确定它应该是什么意思。

    2) 如上所示,不,解释器不会转换为本机机器代码。 JIT 编译器可以。您的处理器仅执行本机机器代码,但本机机器代码可以是读取任意文件并根据内容执行某些操作的程序。从这个意义上说,解释器实际上只是一个以文本文件形式接受输入的典型程序。

    3) JIT 编译非常复杂,而且我根本不是专家。但是,例如,对于 Java 的 HotSpot,代码块必须执行一定次数(客户端 1,500 次,服务器端 15,000 次,IIRC),然后才能调用 JIT 编译器。这很可能是因为实际编译不是免费的,并且很可能已编译的本机机器代码被缓存以供以后执行(这可以解释多次执行的要求)。这使得 JIT 编译是一项投资(在时间和空间上),在第一次执行时可能不会更快(甚至可能更慢),但随后的执行会更快,因为不再需要编译,原生机器码效率更高。

    4) 见上文。

    希望对你有帮助!

    【讨论】:

      【解决方案2】:

      1) 总是说 JIT=runtime,为什么解释器不能在运行时工作?程序运行时,解释器不是在运行时翻译和执行每一行吗?

      你是对的;解释必然发生在运行时。

      2) 总是说 JIT 将非本地代码转换为本地代码,那又如何呢?解释器不会将代码转换为本机代码吗?如果未将指令翻译为本机代码,我的进程如何执行指令?所以解释器也需要将代码翻译成原生代码。

      确实,所有执行最终都是本机代码。解释器充满了实现非本地解释指令效果的函数。这些函数在本机代码中。

      3) 普通的解释器在需要执行时翻译每一行,而使用 JIT 编译器时,每一行在执行之前就被翻译,因此在需要执行该行的那一刻它是可用的。不是吗?

      4) 那么解释器和 JIT 编译器之间的真正区别是什么,它们都在运行时执行程序,都从中间语言翻译为本机代码...

      不同之处在于,JIT 可以应用于大于单个语句或指令的代码段——JIT 可以用于编译整个函数、类,甚至整个程序。

      JIT 编译的优势在于,作为将部分解释代码编译为本机代码的一次性成本,您可以节省解释的执行开销以及利用无法执行的优化当您像解释器那样每次只有一个非本机代码的视图时。

      这就是为什么 JIT 编译重复执行的部分代码是有意义的。编译成本只产生一次,而每次使用代码都会获得收益。

      【讨论】:

        【解决方案3】:

        这里我直接回答最后一个问题。

        有时Java虚拟机被称为Java解释器;然而,鉴于各种方式 可以执行哪些字节码,这个术语可能会产生误导。虽然“Java解释器”是一个合理的 解释字节码的 Java 虚拟机的名称,虚拟机也使用其他技术 (例如即时编译)来执行字节码。因此,虽然所有 Java 解释器都是 Java 虚拟机,但并非所有 Java 虚拟机都是 Java 解释器。

        JIT 指的是少数 JVM 实现中的执行引擎,一种速度更快但需要更多内存的执行引擎,是一种即时编译器。在此方案中,方法的字节码在第一次调用该方法时被编译为本机机器码。然后缓存该方法的本机机器代码,以便下次调用相同的方法时可以重新使用它。

        【讨论】:

        • "虽然所有的 Java 解释器都是 Java 虚拟机,但并不是所有的 Java 虚拟机都是 Java 解释器。"这很混乱,你能用不同的方式解释吗?
        • 跟着这本书“inside-java-virtual-machine”你会清楚地了解JVM
        猜你喜欢
        • 2011-07-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-23
        • 1970-01-01
        相关资源
        最近更新 更多