C#JIT编译和.NET
我对JIT编译器的工作细节有点困惑。 我知道C#编译到IL。 它第一次运行它被JIT'd。 这涉及到它翻译成本地代码? .NET运行时(作为虚拟机?)与JIT代码交互? 我知道这很天真,但我真的很困惑自己。 我的印象一直是组件不是由.NET运行时解释,但我不明白交互的细节。
是的,JIT'ing IL代码涉及将IL转换为本地机器指令。
是的,.NET运行时与JIT的本地机器代码进行交互,这是因为运行时拥有本地机器代码占用的内存块,运行时调用本机机器代码等。
你是正确的.NET运行时不解释你的程序集中的IL代码。
当执行到达一个尚未被JIT编译成本地机器码的函数或代码块(比如,一个if块的else子句)时,会发生什么情况,调用JIT'r以将该IL块编译成本地机器码。 完成后,程序执行进入新发出的机器代码来执行程序逻辑。 如果在执行本地机器代码执行时到达对尚未编译为机器代码的函数的函数调用,则调用JIT'r以“及时”编译该函数。 等等。
JIT'r不一定会将一个函数体的所有逻辑一次编译成机器代码。 如果函数具有if语句,则if或else子句的语句块可能不会被JIT编译,直到执行实际经过该块为止。 尚未执行的代码path将保留IL格式,直到执行完毕。
编译后的本地机器代码保存在内存中,以便在下一段代码执行时再次使用它。 第二次调用函数时,它的运行速度比第一次调用时要快,因为第二次不需要JIT步骤。
在桌面.NET中,本地机器代码在appdomain的生命周期中保存在内存中。 在.NET CF中,如果应用程序内存不足,本机机器码可能会丢失。 在下次执行代码时,它将从原始的IL代码再次编译。
代码被“编译”成微软中间语言,这与汇编格式类似。
当你双击一个可执行文件时,Windows会加载mscoree.dll
,然后设置CLR环境并启动程序的代码。 JIT编译器开始读取程序中的MSIL代码,并将代码dynamic编译为CPU可执行的x86指令。
.NET使用称为MSIL的中间语言,有时缩写为IL。 编译器读取您的源代码并生成MSIL。 当您运行该程序时,.NET即时(JIT)编译器将读取您的MSIL代码并在内存中生成一个可执行的应用程序。 你不会看到这种情况发生,但知道幕后发生了什么是个好主意。
我将通过下面的例子来描述将IL代码编译为本地CPU指令。
public class Example { static void Main() { Console.WriteLine("Hey IL!!!"); } }
主要是CLR知道关于types的每一个细节,以及从这种types调用什么方法,这是由于元数据。
当CLR开始执行IL到本地CPU指令时,CLR为Main的代码引用的每个types分配内部数据结构。
在我们的例子中,我们只有一个types的控制台,因此CLR将通过该内部结构分配一个内部数据结构,我们将pipe理对引用types的访问
在那个数据结构里面,CLR有关于这个types定义的所有方法的条目。 每个条目都包含可以find该方法实现的地址。
当初始化这个结构时,CLR设置CLR本身包含的未logging的FUNCTION中的每个条目。正如你所猜测的,这个FUNCTION 就是我们所说的JIT编译器。
总的来说,你可以考虑将JIT编译器作为CLR函数,将IL编译为本地CPU指令。 让我详细告诉你这个过程将如何在我们的例子。
当Main第一次调用WriteLine时,调用JITCompiler函数。
2.JIT编译器函数知道正在调用什么方法,以及该方法定义了什么types。
3.然后Jit编译器search定义该types的程序集,并在我们的情况下使用ILtypes的WriteLine方法获取该types定义的方法的IL代码。
4.JIT编译器分配DYNAMIC内存块,然后JITvalidation并将IL代码编译为本地CPU代码,并将该代码保存在该内存块中。
5.然后,JIT编译器返回到内部数据结构入口,并用包含本地CPU指令WriteLine的地址新的dynamic创build的内存块来replace地址(主要参考WriteLine的IL代码实现)。
最后,JIT编译器函数跳转到内存块中的代码。 这段代码是WriteLine方法的实现。
7. WriteLine实现后,代码返回到Mains'code继续正常执行。