对JIT编译器和口译员的澄清

时间:2014-05-01 21:46:54

标签: java interpreter jit

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

(口译员)来自维基百科:

  

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

(JIT COMPILER)来自维基百科:

  

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

和来自StackOverFlow:

  

即时编译是将非本机代码(例如字节码)转换为本机代码,然后再执行。

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

3 个答案:

答案 0 :(得分:4)

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

考虑具有两个函数printsleep的编程语言 PrintForPony print函数将一串字符作为唯一参数并将其打印到stdout,而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,在调用JIT编译器之前,代码块必须执行一定次数(客户端为1,500,服务器为15,000,IIRC)。这可能是因为实际的编译不是免费的,而且编译的本机机器代码很可能被缓存以供以后执行(这可以解释许多执行的要求)。这使得JIT编译是一个投资(在时间和空间上),在第一次执行时可能不会更快(甚至可能更慢),但后续执行更快,因为不再需要编译,并且本机机器代码 更有效。

4)见上文。

我希望有所帮助!

答案 1 :(得分:1)

  

1)总是说JIT =运行时,为什么解释器在运行时没有工作?在程序运行时,解释器是否在运行时翻译并执行每一行?

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

  

2)总是说JIT将非本地代码转换为本机代码,那么呢?解释器不是将代码转换为本机代码吗?如果未将指令转换为本机代码,我的进程如何执行指令?因此,解释器也需要将代码转换为本机代码。

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

  

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

     

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

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

JIT编译的优点在于,作为将一部分解释代码编译为本机代码的一次性成本的交换,您节省了解释的执行开销以及利用无法执行的优化当你只有一个非本机代码的单指令视图作为解释器时。

这就是为什么JIT编译重复执行的代码部分是有意义的。编译的成本只发生一次,而每次使用代码都会带来好处。

答案 2 :(得分:0)

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

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

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