[英]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 的一部分。 基本上这就是幕后发生的事情:
现在,当你执行:
JIT 基本上是 CLR 的一部分。 垃圾收集器是另一个。 你把互操作责任等放在什么地方是另一回事,我完全没有资格发表评论:)
我知道这个线程已经很老了,但我想我可以放一张让我理解 JIT 的图片。 它来自Jeffrey Ritcher的优秀书籍CLR via C# 。 图中,他说的元数据是在程序集头中发出的元数据,其中存储了程序集中所有类型的信息:
1)在编译.net程序时,.net程序代码被转换成中间语言(IL)代码
2)在执行程序时,中间语言代码在调用方法时被转换为操作系统本机代码; 这称为 JIT(即时)编译。
2.JIT 是 .NET 的内部编译器,它从 CLR 中获取 MicroSoft 中间代码语言 (MSICL) 代码并将其执行为机器特定指令,而 CLR 作为引擎,其主要任务是向 JIT 提供 MSICL 代码以确保代码是根据机器规格完全编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.