一个Just-in-Time编译器和解释器有什么区别?

47

即时编译器(Just-in-Time-Compiler)和解释器(Interpreter)有什么区别?.NET 和 Java 的 JIT 编译器之间有差异吗?


2
您的问题标题实际上与问题文本不匹配。Java和.NET都是JIT编译的,两者都不是解释型的。 - Aaronaught
它作为第二个问题。 - Rookian
3
那么你应该将其作为第二个不同的问题提出。这样你只会让人们感到困惑。 - Oded
1
把两个问题放在一起是一个问题,而只在标题中放一个问题更加麻烦。人们往往会在标题上搜索,因此完全忽略了你的第二个问题。在我写作时查看答案,包括那两个被删除的答案,你的第二个问题已经完全被忽视了。 - David Thornley
8个回答

60

我发现有时候更抽象的解释会更有帮助。假设你想问墨西哥每个人“你好,你怎么样?”(你的源语言),当然,你首先需要将它翻译成该国的本地语言——西班牙语。这个翻译是“Hola. Como estas?"。

如果你懂西班牙语,那么就不需要进行翻译(本地代码/汇编语言)。你可以直接说“Hola. Como estas?"。

如果你不懂西班牙语,有三种处理方式。

第一种是使用西班牙语词典(一个编译器)在旅行前查询西班牙语单词。也许你发现“Hola. Que tal?"比原句短一个音节(编译器优化),于是你就用了这个短一些的短语。这称作语言编译;你事先将信息转换为本地语言。

第二种方法是你在面对第一个人时,在西班牙语词典中查找单词并记录下来(即时编译)。其优势在于你可以使用普通话词典,然后在中国做同样的实验,而不必带着十张便利贴(不同平台的二进制文件)记录翻译短语。

第三种方法是你在面对每个人时查询单词。本质上,你为每个人单独解释单词(你扮演口译者)。其优势在于任何更改都会立即反映在下一个人身上(你可以改成问“你好。你的狗是什么颜色?”而不需要飞回家并重新开始——你不需要重新编译这些短语)。

  • 事先翻译意味着您可以最快地询问他人(预编译);你甚至不需要把字典带在身边。
  • 当你在每个国家第一次看到一个人时进行翻译,几乎和事先翻译一样快,但仍然可以让你在不需要回家取字典的情况下前往多个国家,但这意味着你需要带上多本字典(一个平台无关的运行时)。
  • 按需翻译速度较慢,但允许您在不回家的情况下更改单词(源分布式语言)。

1
太棒了,我喜欢这个答案。其他的都太技术化了,会让非程序员感到困惑。 - Michiel van der Blonk
当我在中国使用普通话时,我该如何利用存储的(西班牙语)结果? - Teemoh
1
啊,好的,我想我明白了……只要我在墨西哥,我就使用存储的结果? - Teemoh
这是一个很棒的解释!只有一个问题...什么是源分布式语言?我找不到明确的定义。 - Aesop

38

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

维基百科介绍如下:

JIT 建立在运行时环境中两个早期想法的基础上:字节码编译和动态编译。它在运行时将代码转换为本机代码,例如将字节码转换为本机机器代码,然后再执行。

解释器执行程序。它可能具有JIT,也可能没有。

同样来自维基百科:

解释器可能是一个程序,

  1. 直接执行源代码
  2. 将源代码翻译成一些有效的中间表示形式(代码),然后立即执行此代码
  3. 明确地执行由解释器系统的编译器创建的存储的预编译代码

标准的Java和.NET发行版都具有JIT编译,但这不是标准所要求的。.NET和C#中的JIT编译器当然是不同的,因为中间字节码是不同的,但原理是相同的。


CLR的JIT编译器是否会一次性编译整个代码? - Rookian
3
不,它只编译必要的代码。这使你能够在运行时进行优化。 - Kimi
但是优化过程每次调用只发生一次,不是吗(.NET JIT)?因为我读过 .NET JIT 只编译一段代码一次。 - Rookian
3
对于 JIT 等新手来说,这可能会让人产生误导,因为它并没有明确说明区别:解释器就像是一个程序,使用您的源代码作为指南来确定调用哪个“自己”的子程序。这就是为什么它被称为“解释器”。另一方面,JIT 将所有源代码直接转换为本地代码。 - Antun Tun
1
第1点和第3点不是一样的吗?我的意思是,解释器怎么能执行代码而不进行某种形式的翻译并使用已经存在的东西呢? - Teemoh

24

解释器会为每个指令即时生成并执行机器码指令,无论该指令是否已经被执行过。


JIT 会缓存已经被翻译成机器码的指令,并重复使用这些本地机器码指令,从而节省时间和资源,无需重新解释已经被解释过的语句。


1
你的回答与Java JIT编译器有关,不是吗? - Rookian
是的,但我相信JIT技术最初是在Smalltalk上开发的。 - crowne
那么 JIT 会导致程序运行时间越长,速度就越快? - temporary_user_name
不一定,因为程序中可能存在某些逻辑导致其运行缓慢。JIT 不会改变这些逻辑。但至少将逻辑转换为机器码所花费的 CPU 周期成本只会发生一次。 - crowne

9

简而言之:

解释器:一次只能执行一条指令。

即时编译:一次性接收一整块代码,并在执行前编译。因此有更多的优化空间。


因此,两者的区别主要在于代码编译优化。对于JIT来说,一段代码被编译并优化,而解释器则不进行任何优化。 - SmAxlL

8
执行引擎是编译器还是解释器的问题,可以通过考虑如果一个例程被执行了1000次会发生什么来简单回答。如果执行引擎内部的代码必须对某个特定代码表示进行1000次检查,那么执行引擎就是该表示形式的解释器。如果执行引擎内的代码只需要检查该表示形式的代码少量的次数(通常只有一次,尽管不一定),那么它就是该表示形式的编译器或翻译器。请注意,执行引擎通常会将输入代码转换为可以更容易检查的其他形式。这样的执行引擎将把前一种形式的编译器或翻译器与后一种形式的解释器结合起来。
请注意,解释器很少产生任何形式的机器码。除非语句需要执行一些无法用其他方式完成的操作,否则解释器几乎不会生成机器码。例如,如果在8080上运行的BASIC解释器遇到“OUT 100,5”指令,它通常会通过在某个固定地址的连续三个字节中存储D3 64 C9(OUT 64h / RET),将A加载为5,并调用该地址来执行该操作。尽管解释器可能会技术性地生成机器码,但如果对同一OUT指令执行500次,解释器将不得不每次重新生成机器码。

3

JIT编译器生成将块源代码转换为二进制机器码。解释器逐行翻译。


1
当第一次引用类时,JIT执行引擎会重新编译由Java编译器生成的包含JVM指令集的.class文件(主要二进制文件),将其编译为包含主机系统指令集的二进制文件。JIT将这些重新编译后的二进制文件存储并重复使用,从而减少解释时间,并从本地代码执行中受益。
另一方面,普通的Java解释器逐个解释来自类文件的JVM指令,并针对其调用一个过程。
http://bitshub.blogspot.com/2010/01/Flavors-of-JVM.html这里找到详细的比较。

0

当您编译 Microsoft.NET 语言时,编译器会生成用 Microsoft Intermediate Language (MSIL) 编写的代码。MSIL 是一组指令,可以快速转换为本机代码。

只有在将 MSIL 代码转换为本机机器代码后,Microsoft.NET 应用程序才能运行。在 .NET Framework 中,中间语言在应用程序或组件运行时即时编译成本机代码(JIT),而不是在开发时编译应用程序。

更多信息


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接