我对JIT编译器如何工作的细节感到有点困惑。我知道C#可以编译成IL。它第一次运行的时候是JIT的,这是否涉及到将它转换成本机代码?.NET运行时(作为虚拟机?)与JIT的代码交互?我知道这很天真,但我真的把自己搞糊涂了。我的印象一直是.NET运行库不会解释这些程序集,但我不理解交互的细节。
发布于 2011-04-08 10:02:20
是的,即时IL代码涉及将IL转换为本机机器指令。
是的,.NET运行时与即时本机代码交互,在某种意义上,运行时拥有本机代码占用的内存块,运行时调用本机代码,等等。
.NET运行时不会解释程序集中的IL代码,这一点是正确的。
当执行到达尚未JIT编译为本机代码的函数或代码块(如if块的else子句)时,将调用JIT'r将该IL块编译为本机代码。完成后,程序执行进入新发出的机器码来执行它的程序逻辑。如果在执行本机机器代码时遇到对尚未编译为机器代码的函数的函数调用,则会调用JIT'r来“及时”编译该函数。诸若此类。
JIT'r不一定要一次将函数体的所有逻辑编译成机器码。如果函数有If语句,if或else子句的语句块可能不会被JIT编译,直到执行实际通过该块。尚未执行的代码路径在执行之前将一直保持为IL形式。
编译后的本机代码保存在内存中,以便下次执行该段代码时可以再次使用。第二次调用函数时,它会比第一次调用时运行得更快,因为第二次调用时不需要任何JIT步骤。
在桌面.NET中,本机机器代码在应用程序域的生命周期内一直保存在内存中。在.NET CF中,如果应用程序内存不足,则可能会丢弃本机代码。下次执行通过该代码时,它将从原始的IL代码再次进行JIT编译。
发布于 2011-04-08 09:22:07
代码被“编译”成类似于汇编格式的Microsoft中间语言。
当你双击一个可执行文件时,Windows加载mscoree.dll,然后设置CLR环境并启动你的程序代码。即时编译器开始读取程序中的MSIL代码,并动态地将代码编译成x86指令,CPU可以执行这些指令。
发布于 2017-06-16 04:09:57
我将通过下面的例子描述如何将IL代码编译成本机CPU指令。
public class Example
{
static void Main()
{
Console.WriteLine("Hey IL!!!");
}
}首先,CLR知道关于类型的每个细节,以及从该类型调用的方法,这是由于元数据。
当CLR开始执行IL into本机CPU指令时,CLR会为Main代码引用的每个类型分配内部数据结构。
在我们的示例中,我们只有一种类型的控制台,因此CLR将分配一个内部数据结构。通过该内部结构,我们将管理对引用类型的访问。
在该数据结构中,CLR具有关于该类型定义的所有方法的条目。每个条目都保存了方法实现所在的地址。
在初始化此结构时,CLR会在CLR本身中包含的未记录的函数中设置每个条目。正如你可以猜到的,这个函数就是我们所说的即时编译器。
总的来说,你可以把JIT编译器看作是一个CLR函数,它将IL编译到本机CPU指令中。让我在我们的示例中详细地向您展示这个过程。
1.当Main第一次调用WriteLine时,将调用JITCompiler函数。
2. this编译器函数知道调用的是什么方法,以及什么类型定义了这个方法。
3.然后,Jit Compiler搜索定义了该类型的程序集,并获取由该类型定义的方法的IL代码,在本例中为WriteLine方法的IL代码。
4.JIT编译器分配动态内存块,在此之后,JIT验证并将IL代码编译成本地CPU码,并将该CPU码保存在该内存块中。
5.然后,JIT编译器返回到内部数据结构条目,并将地址(主要引用WriteLine的IL代码实现)替换为新的动态创建的内存块,其中包含WriteLine的本机CPU指令。
6.最后,JIT编译器函数跳转到内存块中的代码并执行writeline方法的本机代码。
7.执行完WriteLine后,代码返回到Main的代码,Main的代码照常继续执行。
https://stackoverflow.com/questions/5589409
复制相似问题