繁体   English   中英

CLR 与 JIT

[英]CLR vs JIT

JIT 编译器和 CLR 有什么区别? 如果您将代码编译为 il 并且 CLR 运行该代码,那么 JIT 在做什么? 将泛型添加到 CLR 后,JIT 编译有何变化?

您将代码编译为 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 之上运行多种不同语言的原因

JIT 是 CLR 的一方面。

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

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

解决泛型的添加问题。

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

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

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

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

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

正如 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... 依此类推...

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

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

通过 C# 来自 CLR 的 JIT 图像

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

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

  1. Common Language Runtime(CLR) 是解释器,而 Just In Time(JIT) 是 .Net Framework 中的编译器。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM