54

JIT 编译器和 CLR 有什么区别?如果您将代码编译为 il 并且 CLR 运行该代码,那么 JIT 在做什么?随着向 CLR 添加泛型,JIT 编译发生了怎样的变化?

4

7 回答 7

83

您将代码编译为 IL,IL 在运行时执行并编译为机器代码,这就是所谓的 JIT。

编辑,进一步充实答案(仍然过于简化):

当您在 Visual Studio 中编译 C# 代码时,它会变成 CLR 可以理解的 IL,IL 对于在 CLR 之上运行的所有语言都是相同的(这使得 .NET 运行时能够使用多种语言和互操作他们之间很容易)。

在运行时,IL 被解释为机器代码(特定于您所在的体系结构),然后执行。这个过程被称为 Just In Time 编译或简称 JIT。只有需要的 IL 被转换成机器码(而且只有一次,一旦它被编译成机器码就会被“缓存”),就在它被执行之前的时间,因此得名 JIT。

这就是 C# 的样子

C# 代码>C# 编译器>IL >.NET 运行时>JIT 编译器>机器代码>执行

这就是 VB 的样子

VB 代码>VB 编译器>IL >.NET 运行时>JIT 编译器>机器码>执行

正如您所看到的,每种语言只有前两个步骤是唯一的,并且在转换为 IL 之后的所有内容都是相同的,正如我之前所说,这就是您可以在 .NET 之上运行几种不同语言的原因

于 2009-03-02T11:19:18.140 回答
54

JIT 是 CLR 的一个方面。

具体来说,它负责将由原始语言的编译器(例如 Microsoft c# 的 csc.exe)生成的 CIL(以下称为 IL)更改为当前处理器的本机代码(以及它在当前进程中公开的架构,例如例如 32/64 位)。如果有问题的程序集是 ngen 的,那么 JIT 过程是完全没有必要的,没有它,CLR 将很好地运行此代码。

在使用尚未从中间表示转换的方法之前,JIT 有责任对其进行转换。JIT 的
确切启动时间是特定于实现的,并且可能会发生变化。然而,CLR 设计要求 JIT在相关代码执行之前发生,相比之下,JVM 可以在一段时间内自由解释代码,而单独的线程创建机器代码表示。
“正常” CLR 使用预 JIT 存根方法其中 by 方法仅在使用时进行 JIT 编译。这涉及让初始本地方法存根成为间接指示 JIT 编译该方法,然后修改原始调用以跳过初始存根。当前的精简版在加载时编译类型的所有方法。

解决泛型的添加问题。

这是 IL 规范和 JIT 在其语义方面的最后一次重大更改,而不是其内部实现细节。

添加了几个新的 IL 指令,并为检测类型和成员提供了更多元数据选项。在 IL 级别也添加了约束。

当 JIT 编译具有通用参数的方法(显式或隐式通过包含类)时,它可能为使用的每种类型设置不同的代码路径(机器代码指令)。实际上,JIT 对所有引用类型使用共享实现,因为这些引用类型的变量将表现出相同的语义并占用相同的空间 (IntPtr.Size)。

每种值类型都会为其生成特定的代码,处理堆栈/堆上变量的减少/增加大小是造成这种情况的主要原因。此外,通过在方法调用之前发出受约束的操作码,对非引用类型的许多调用不需要封装值来调用方法(这种优化也用于非通用情况)。这也允许<T>正确处理默认行为,并在使用非 Nullable 值类型时将与 null 的比较剥离为无操作(始终为 false)。

如果在运行时尝试通过反射创建泛型类型的实例,则类型参数将由运行时验证以确保它们通过任何约束。这不会直接影响 JIT,除非在类型系统中使用它(尽管可能)。

于 2009-03-02T12:16:08.410 回答
31

正如 Jon Skeet 所说,JIT 是 CLR 的一部分。基本上这就是幕后发生的事情:

  1. 您的源代码被编译成称为通用中间语言 (CIL) 的字节码。
  2. 来自每个类和每个方法(以及所有其他事物:O)的元数据都包含在生成的可执行文件(无论是 dll 还是 exe)的 PE 头中。
  3. 如果您正在生成可执行文件,PE Header 还包括一个传统的引导程序,该引导程序负责在您执行可执行文件时加载 CLR(公共语言运行时)。

现在,当您执行时:

  1. 引导程序初始化 CLR(主要通过加载 mscorlib 程序集)并指示它执行您的程序集。
  2. CLR 执行您的主条目。
  3. 现在,类有一个向量表,其中保存了方法函数的地址,因此当您调用 MyMethod 时,会搜索该表,然后对该地址进行相应的调用。在开始时,所有表的所有条目都具有 JIT 编译器的地址。
  4. 当调用此类方法之一时,将调用 JIT 而不是实际方法并获得控制权。然后,JIT 将 CIL 代码编译为适合架构的实际汇编代码。
  5. 一旦代码被编译,JIT 就会进入方法向量表,并将地址替换为已编译代码的地址,这样每个后续调用都不再调用 JIT。
  6. 最后,JIT 处理编译代码的执行。
  7. 如果您调用另一个尚未编译的方法,则返回 4... 等等...
于 2009-03-02T11:36:44.573 回答
28

JIT 基本上是 CLR 的一部分。垃圾收集器是另一个。你把互操作责任等放在哪里是另一回事,我完全没有资格发表评论:)

于 2009-03-02T11:23:29.083 回答
18

我知道线程已经很老了,但我想我可能会放入让我理解 JIT 的图片。它来自Jeffrey Ritcher 通过 C# 编写的优秀书籍CLR 。在图片中,他所说的元数据是在程序集头中发出的元数据,其中存储了有关程序集类型的所有信息:

通过 C# 来自 CLR 的 JIT 图像

于 2011-02-24T20:51:07.900 回答
2

1)在编译.net程序时,将.net程序代码转换为中间语言(IL)代码

2)在执行程序时,中间语言代码在调用方法时转换为操作系统本地代码;这称为 JIT(即时)编译。

于 2012-03-09T12:40:23.367 回答
-2
  1. 公共语言运行时(CLR)是解释器,而即时(JIT)是.Net Framework中的编译器。

2.JIT是.NET的内部编译器,它从CLR获取微软中间代码语言(MSICL)代码并执行它以机器特定的指令,而CLR作为一个引擎,它的主要任务是向JIT提供MSICL代码以确保代码是根据机器规格完全编译。

于 2014-05-05T17:55:14.320 回答