问题描述
JIT 编译器和 CLR 有什么区别?如果您将代码编译为 il 并且 CLR 运行该代码,那么 JIT 在做什么?向 CLR 添加泛型后,JIT 编译有何变化?
What is the difference between the JIT compiler and CLR? If you compile your code to il and CLR runs that code then what is the JIT doing? How has JIT compilation changed with the addition of generics to the CLR?
推荐答案
JIT 是 CLR 的一个方面.
The JIT is one aspect of the CLR.
具体来说,它负责将原始语言的编译器(例如 Microsoft c# 的 csc.exe)生成的 CIL(以下称为 IL)更改为当前处理器(以及它在当前处理器中公开的体系结构)的本机代码进程,例如 32/64 位).如果有问题的程序集是 ngen 的,那么 JIT 过程是完全没有必要的,没有它,CLR 将运行此代码.
Specifically it is the part responsible for changing CIL (hereafter called IL) produced by the original language's compiler (csc.exe for Microsoft c# for example) into machine code native to the current processor (and architecture that it exposes in the current process, for example 32/64bit). If the assembly in question was ngen'd then the the JIT process is completely unnecessary and the CLR will run this code just fine without it.
在使用尚未从中间表示转换的方法之前,JIT 有责任对其进行转换.
何时 JIT 将启动是特定于实现的,并且可能会发生变化.然而,CLR 设计要求 JIT在相关代码执行之前发生,相比之下,JVM 可以在一段时间内自由解释代码,而单独的线程会创建机器代码表示.
正常" CLR 使用 pre-JIT 存根方法,其中方法仅在使用时进行 JIT 编译.这涉及让初始本地方法存根成为间接指示 JIT 编译该方法,然后修改原始调用以跳过初始存根.当前的精简版会在加载类型时编译该类型的所有方法.
Before a method is used which has not yet been converted from the intermediate representation it is the JIT's responsibility to convert it.
Exactly when the JIT will kick in is implementation specific, and subject to change. However the CLR design mandates that the JIT happens before the relevant code executes, JVMs in contrast would be free to interpret the code for a while while a separate thread creates a machine code representation.
The 'normal' CLR uses a pre-JIT stub approach where by methods are JIT compiled only as they are used. This involves having the initial native method stub be an indirection to instruct the JIT to compile the method then modify the original call to skip past the initial stub. The current compact edition instead compiles all methods on a type when it is loaded.
解决泛型的添加问题.
这是 IL 规范和 JIT 在语义方面的最后一次重大更改,而不是其内部实现细节.
This was the last major change to the IL specification and JIT in terms of its semantics as opposed to its internal implementation details.
添加了几个新的 IL 指令,并为检测类型和成员提供了更多元数据选项.在 IL 级别也添加了约束.
Several new IL instructions were added, and more meta data options were provided for instrumenting types and members. Constraints were added at the IL level as well.
当 JIT 编译具有通用参数的方法(通过包含类显式或隐式)时,它可能为使用的每种类型设置不同的代码路径(机器代码指令).实际上,JIT 对所有引用类型使用共享实现,因为这些引用类型的变量将表现出相同的语义并占用相同的空间 (IntPtr.Size).
When the JIT compiles a method which has generic arguments (either explicitly or implicitly through the containing class) it may set up different code paths (machine code instructions) for each type used. In practice the JIT uses a shared implementation for all reference types since variables for these will exhibit the same semantics and occupy the same space (IntPtr.Size).
每种值类型都会为其生成特定的代码,处理堆栈/堆上变量大小的减少/增加是造成这种情况的主要原因.此外,通过在方法调用之前发出受约束的操作码,对非引用类型的许多调用不需要封装值来调用方法(这种优化也用于非通用情况).这也允许正确处理默认的<T>
行为,并在使用非 Nullable 值类型时将与 null 的比较作为无操作(始终为 false)剥离.
Each value type will get specific code generated for it, dealing with the reduced / increased size of the variables on the stack/heap is a major reason for this. Also by emitting the constrained opcode before method calls many invocations on non reference types need not box the value to call the method (this optimization is used in non generic cases as well). This also allows the default<T>
behaviour to be correctly handled and for comparisons to null to be stripped out as no ops (always false) when a non Nullable value type is used.
如果在运行时尝试通过反射创建泛型类型的实例,则类型参数将由运行时验证以确保它们通过任何约束.这不会直接影响 JIT,除非在类型系统中使用它(尽管可能).
If an attempt is made at runtime to create an instance of a generic type via reflection then the type parameters will be validated by the runtime to ensure they pass any constraints. This does not directly affect the JIT unless this is used within the type system (unlikely though possible).
这篇关于CLR 与 JIT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!