我对JIT编译器的工作原理有点困惑。我知道C#编译成IL。第一次运行它是JIT'd。这是否涉及将其翻译成本机代码? .NET运行时(作为虚拟机吗?)是否与JIT代码交互?我知道这很天真,但我真的很困惑。我的印象一直是.NET运行时没有解释程序集,但我不了解交互的细节。
答案 0 :(得分:70)
是的,JIT的IL代码涉及将IL转换为本机机器指令。
是的,.NET运行时与JIT的本机机器代码交互,因为运行时拥有本机机器代码占用的内存块,运行时调用本机机器代码等等。
您认为.NET运行时不解释程序集中的IL代码是正确的。
当执行到达一个尚未被JIT编译成本机机器代码的函数或代码块(比如if块的else子句)时,会调用JIT'r来编译IL的块。本地机器代码。完成后,程序执行进入刚刚发出的机器代码以执行它的程序逻辑。如果在执行本机机器代码执行时到达对尚未编译为机器代码的函数的函数调用,则调用JIT'r以“及时”编译该函数。等等。
JIT'r不一定将函数体的所有逻辑编译成机器代码。如果函数具有if语句,则在执行实际通过该块之前,if或else子句的语句块可能不会被JIT编译。未执行的代码路径在执行之前保持IL格式。
已编译的本机机器代码保存在内存中,以便下次执行该代码段时可以再次使用它。第二次调用函数时,它将比第一次调用它时运行得更快,因为第二次不需要JIT步骤。
在桌面.NET中,本地计算机代码在应用程序域的生命周期内保留在内存中。在.NET CF中,如果应用程序内存不足,则可能会丢弃本机机器代码。在下次执行该代码时,将从原始IL代码再次编译JIT。
答案 1 :(得分:20)
代码是"编译"进入Microsoft中间语言,类似于汇编格式。
当您双击可执行文件时,Windows会加载mscoree.dll
,然后设置CLR环境并启动您的程序代码。 JIT编译器开始读取程序中的MSIL代码,并将代码动态编译为x86指令,CPU可以执行这些指令。
答案 2 :(得分:1)
.NET使用名为MSIL的中间语言,有时缩写为IL。编译器读取您的源代码并生成MSIL。当您运行该程序时,.NET即时(JIT)编译器将读取您的MSIL代码并在内存中生成可执行应用程序。你不会看到任何这种情况发生,但是知道幕后发生的事情是个好主意。
答案 3 :(得分:0)
我将通过以下示例描述将IL代码编译为本机CPU指令。
public class Example
{
static void Main()
{
Console.WriteLine("Hey IL!!!");
}
}
主要是CLR知道有关类型的所有细节以及从该类型调用的方法,这是由元数据引起的。
当CLR开始执行IL到本机CPU指令时,CLR为Main的代码引用的每个类型分配内部数据结构。
在我们的例子中,我们只有一种类型的控制台,因此CLR将通过该内部结构分配一个内部数据结构,我们将管理对引用类型的访问
在该数据结构内部CLR具有关于该类型定义的所有方法的条目。每个条目都包含可以找到方法实现的地址。
初始化此结构时,CLR会在CLR本身内部包含未记录的 FUNCTION 中的每个条目。正如您可以猜到的那样, FUNCTION 就是我们所说的JIT编译器强>
总的来说,您可以将JIT Compiler视为CLR函数,它将IL编译为本机CPU指令。让我详细介绍一下这个过程在我们的例子中的作用。
1.当Main首次调用WriteLine时,调用JITCompiler函数。
2.JIT编译器函数知道调用什么方法以及定义此方法的类型。
3.然后,Jit Compiler搜索定义该类型的程序集,并在我们的案例ILL的WriteLine方法代码中获取该类型定义的方法的IL代码。
4.JIT编译器分配 DYNAMIC 内存块,之后JIT验证并将IL代码编译为本机CPU代码并将该CPU代码保存在该内存块中。
5.然后,JIT编译器返回内部数据结构条目,并将地址(主要引用WriteLine的IL代码实现)替换为地址新动态创建的内存块,其中包含WriteLine的本机CPU指令。
6.最后,JIT编译器函数跳转到内存块中的代码。 此代码是WriteLine方法的实现。
7.执行WriteLine后,代码返回Mains'code,继续正常执行。
答案 4 :(得分:0)
.NET Framework使用CLR环境生成MSIL(Microsoft中间语言),也称为IL。 编译器读取您的源代码,并在您构建/编译项目时生成MSIL。 现在,当您最终运行项目时,.NET JIT(Just-in-time Compiler)开始起作用。 JIT读取您的MSIL代码并生成可以由CPU轻松执行的本机代码(x86指令).JIT读取所有MSIL指令并逐行执行它们。
如果您有兴趣看看,幕后发生的事情,我们已经回答了。请关注-Here