C# CLR 与 JIT
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/601974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CLR vs JIT
提问by Ted Smith
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 有什么区别?如果您将代码编译为 il 并且 CLR 运行该代码,那么 JIT 在做什么?将泛型添加到 CLR 后,JIT 编译有何变化?
采纳答案by ShuggyCoUk
The JIT is one aspect of the CLR.
JIT 是 CLR 的一方面。
Specifically it is the part responsible for changing CIL/MSIL (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.
具体来说,它负责将原始语言的编译器(例如 Microsoft c# 的 csc.exe)生成的 CIL/MSIL(以下称为 IL)更改为当前处理器本地的机器代码(以及它在当前进程中公开的架构) ,例如 32/64 位)。如果有问题的程序集是 ngen'd,那么 JIT 过程是完全不必要的,CLR 将在没有它的情况下运行此代码。
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 whenthe JIT will kick in is implementation specific, and subject to change. However the CLR design mandates that the JIT happens beforethe relevant code executes, JVM's 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 approachwhere 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.
在使用尚未从中间表示转换的方法之前,JIT 负责转换它。JIT 启动的
确切时间是特定于实现的,并且可能会发生变化。然而,CLR 设计要求 JIT在相关代码执行之前发生,相比之下,JVM 可以自由地解释代码一段时间,而单独的线程创建机器代码表示。
“正常” CLR 使用预 JIT 存根方法其中 by 方法仅在使用时进行 JIT 编译。这涉及将初始本地方法存根作为间接方法,以指示 JIT 编译该方法,然后修改原始调用以跳过初始存根。当前的精简版会在加载类型时编译该类型的所有方法。
To address the addition of Generics.
解决泛型的添加问题。
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 规范和 JIT 在语义方面的最后一次重大更改,而不是其内部实现细节。
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.
添加了几个新的 IL 指令,并为检测类型和成员提供了更多元数据选项。在 IL 级别也添加了约束。
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).
当 JIT 编译具有泛型参数的方法(通过包含类显式或隐式)时,它可能为所使用的每种类型设置不同的代码路径(机器代码指令)。在实践中,JIT 对所有引用类型使用共享实现,因为这些变量将表现出相同的语义并占用相同的空间 (IntPtr.Size)。
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.
每个值类型都会为其生成特定的代码,处理堆栈/堆上变量大小的减小/增加是造成这种情况的主要原因。同样通过在方法调用之前发出受约束的操作码,对非引用类型的许多调用不需要装箱调用方法的值(这种优化也用于非通用情况)。这也允许<T>
正确处理默认行为,并在使用非 Nullable 值类型时将与 null 的比较剥离为无操作(始终为 false)。
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).
如果在运行时尝试通过反射创建泛型类型的实例,则类型参数将由运行时验证以确保它们通过任何约束。这不会直接影响 JIT,除非它在类型系统中使用(虽然可能不太可能)。
回答by thr
You compile your code to IL which gets executed and compiled to machine code during runtime, this is what's called JIT.
您将代码编译为 IL,后者在运行时执行并编译为机器代码,这就是所谓的 JIT。
Edit, to flesh out the answer some more (still overly simplified):
编辑,以充实答案(仍然过于简化):
When you compile your C# code in visual studio it gets turned into IL that the CLR understands, the IL is the same for all languages running on top of the CLR (which is what enables the .NET runtime to use several languages and inter-op between them easily).
当你在 Visual Studio 中编译你的 C# 代码时,它会变成 CLR 理解的 IL,IL 对于运行在 CLR 之上的所有语言都是相同的(这使得 .NET 运行时能够使用多种语言和互操作他们之间很容易)。
During runtime the IL is interpreted into machine code (which is specific to the architecture you're on) and then it's executed. This process is called Just In Time compilation or JIT for short. Only the IL that is needed is transformed into machine code (and only once, it's "cached" once it's compiled into machinecode), just in timebefore it's executed, hence the name JIT.
在运行时,IL 被解释为机器代码(特定于您所在的架构),然后被执行。这个过程称为Just In Time 编译或简称JIT。只有需要的 IL 被转换成机器代码(并且只有一次,一旦它被编译成机器代码就会被“缓存”),就在它被执行之前,因此得名 JIT。
This is what it would look like for C#
这就是 C# 的样子
C# Code
>
C# Compiler>
IL>
.NET Runtime>
JIT Compiler>
Machinecode>
Execution
C# 代码
>
C# 编译器>
IL>
.NET 运行时>
JIT 编译器>
机器代码>
执行
And this is what it would look like for VB
这就是 VB 的样子
VB Code
>
VB Compiler>
IL>
.NET Runtime>
JIT Compiler>
Machinecode>
Execution
VB 代码
>
VB 编译器>
IL>
.NET 运行时>
JIT 编译器>
机器代码>
执行
And as you can see only the two first steps are unique to each language, and everything after it's been turned into IL is the same which is, as I said before, the reason you can run several different languages on top of .NET
正如你所看到的,每种语言只有前两个步骤是独一无二的,而在它变成 IL 之后的一切都是一样的,正如我之前所说,这就是你可以在 .NET 之上运行多种不同语言的原因
回答by Jon Skeet
The JIT is basically partof the CLR. The garbage collector is another. Quite where you put interop responsibilities etc is another matter, and one where I'm hugely underqualified to comment :)
JIT 基本上是 CLR 的一部分。垃圾收集器是另一个。你把互操作责任等放在什么地方是另一回事,我完全没有资格发表评论:)
回答by Jorge Córdoba
As Jon Skeet says, JIT is part of the CLR. Basically this is what is happening under the hood:
正如 Jon Skeet 所说,JIT 是 CLR 的一部分。基本上这就是幕后发生的事情:
- Your source code is compiled into a byte code know as the common intermediate language (CIL).
- Metadata from every class and every methods (and every other thing :O) is included in the PE header of the resulting executable (be it a dll or an exe).
- If you're producing an executable the PE Header also includes a conventional bootstrapper which is in charge of loading the CLR (Common language runtime) when you execute you executable.
- 您的源代码被编译成称为公共中间语言 (CIL) 的字节码。
- 来自每个类和每个方法(以及其他所有东西:O)的元数据都包含在生成的可执行文件(无论是 dll 还是 exe)的 PE 标头中。
- 如果您正在生成可执行文件,PE Header 还包括一个传统的引导程序,它负责在您执行可执行文件时加载 CLR(公共语言运行时)。
Now, when you execute:
现在,当你执行:
- The bootstraper initializes the CLR (mainly by loading the mscorlib assembly) and instructs it to execute your assembly.
- The CLR executes your main entry.
- Now, classes have a vector table which hold the addresses of the method functions, so that when you call MyMethod, this table is searched and then a corresponding call to the address is made. Upon start ALL entries for all tables have the address of the JIT compiler.
- When a call to one of such method is made, the JIT is invoked instead of the actual method and takes control. The JIT then compiles the CIL code into actual assembly code for the appropiate architecture.
- Once the code is compiled the JIT goes into the method vector table and replaces the address with the one of the compiled code, so that every subsequent call no longer invokes the JIT.
- Finally, the JIT handles the execution to the compiled code.
- If you call another method which haven't yet being compiled then go back to 4... and so on...
- 引导程序初始化 CLR(主要通过加载 mscorlib 程序集)并指示它执行您的程序集。
- CLR 执行您的主条目。
- 现在,类有一个保存方法函数地址的向量表,因此当您调用 MyMethod 时,会搜索该表,然后对该地址进行相应的调用。开始时,所有表的所有条目都具有 JIT 编译器的地址。
- 当调用此类方法之一时,将调用 JIT 而不是实际方法并取得控制权。然后 JIT 将 CIL 代码编译成适合架构的实际汇编代码。
- 一旦代码被编译,JIT 就会进入方法向量表,并用已编译的代码之一替换地址,以便每个后续调用不再调用 JIT。
- 最后,JIT 处理编译代码的执行。
- 如果您调用另一个尚未编译的方法,则返回到 4... 依此类推...
回答by Punit Vora
I know the thread is pretty old, but I thought I might put in the picture that made me understand JIT. It's from the excellent book CLR via C# by Jeffrey Ritcher. In the picture, the metadata he is talking about is the metadata emitted in the assembly header where all information about types in the assembly is stored:
我知道这个线程已经很老了,但我想我可以放一张让我理解 JIT 的图片。它来自Jeffrey Ritcher的优秀书籍CLR via C#。图中,他说的元数据是在程序集头中发出的元数据,其中存储了程序集中所有类型的信息:
回答by ravindranath
1)while compiling the .net program,.net program code is converted into Intermediate Language(IL) code
1)在编译.net程序时,.net程序代码被转换成中间语言(IL)代码
2)upon executing the program the Intermediate language code is converted into operating system Native code as and when a method is called; this is called JIT (Just in Time) compilation.
2)在执行程序时,中间语言代码在调用方法时被转换为操作系统本机代码;这称为 JIT(即时)编译。
回答by MERLIN THOMAS
- Common Language Runtime(CLR) is interpreter while Just In Time(JIT) is compiler in .Net Framework.
- Common Language Runtime(CLR) 是解释器,而 Just In Time(JIT) 是 .Net Framework 中的编译器。
2.JIT is the internal compiler of .NET which takes MicroSoft Intermediate Code Language (MSICL) code from CLR and executes it to machine specific instructions whereas CLR works as an engine its main task is to provide MSICL code to JIT to ensure that code is fully compiled as per machine specification.
2.JIT 是 .NET 的内部编译器,它从 CLR 中获取 MicroSoft 中间代码语言 (MSICL) 代码并将其执行为机器特定指令,而 CLR 作为引擎,其主要任务是向 JIT 提供 MSICL 代码以确保代码是根据机器规格完全编译。