CLR与JIT

时间:2009-03-02 11:16:45

标签: c# compiler-construction clr jit

JIT编译器和CLR有什么区别?如果您将代码编译为il并且CLR运行该代码,那么JIT正在做什么? JIT编译如何通过向CLR添加泛型来改变?

7 个答案:

答案 0 :(得分:73)

您将代码编译为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

答案 1 :(得分:46)

JIT是CLR的一个方面。

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

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

解决泛型的问题。

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

添加了几条新的IL指令,并为仪表类型和成员提供了更多元数据选项。 在IL水平上也增加了约束。

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

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

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

答案 2 :(得分:29)

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

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

    1. bootstraper初始化CLR(主要通过加载mscorlib程序集)并指示它执行程序集。
    2. CLR执行您的主条目。
    3. 现在,类有一个向量表,其中包含方法函数的地址,因此当您调用MyMethod时,将搜索此表,然后对该地址进行相应的调用。启动后,所有表的所有条目都具有JIT编译器的地址。
    4. 当调用其中一个方法时,调用JIT而不是实际方法并控制。然后,JIT将CIL代码编译为适当架构的实际汇编代码。
    5. 编译代码后,JIT进入方法向量表,并将地址替换为其中一个已编译的代码,以便每个后续调用不再调用JIT。
    6. 最后,JIT处理已编译代码的执行。
    7. 如果您调用另一个尚未编译的方法,请返回4 ...依此类推......

答案 3 :(得分:26)

JIT基本上是CLR的部分。垃圾收集器是另一个。你把互操作责任等放在哪里是另一回事,而且我很不容易发表评论:)

答案 4 :(得分:15)

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

JIT image from CLR via C#

答案 5 :(得分:2)

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

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

答案 6 :(得分:-2)

  1. 公共语言运行时(CLR)是解释器,而Just In Time(JIT)是.Net Framework中的编译器。
  2. 2.JIT是.NET的内部编译器,它从CLR获取MicroSoft中间代码语言(MSICL)代码并执行它以处理特定指令,而CLR作为引擎工作,其主要任务是向JIT提供MSICL代码以确保该代码根据机器规范进行了完全编译。