JIT编译:它是什么以及它如何工作。
编译器有两种类型:进行显式编译的编译器和进行隐式编译的编译器。
显式编译是编译器将源代码直接转换为CPU可以理解的机器代码时的过程。C和C ++编译器是显式编译的绝佳示例。
隐式编译是一个分为两个步骤的过程,它要求虚拟机能够执行您的代码。该过程的第一步是将程序转换为虚拟机可以理解的字节码。.NET字节码称为通用中间语言或CIL。它也被称为Microsoft中间语言(MSIL)或仅仅是中间语言(IL)。我将使用其正式名称通用中间语言(CIL)。第一步由编译器(C#,VB.NET等)完成。
第二步是将CIL代码转换为在金属上运行的机器代码。这是虚拟机的任务。公共语言运行时(.NET虚拟机)在运行时仅将执行的CIL片段转换为CPU指令。
即时编译
即时编译将CIL转换为机器代码转换的过程。在.NET世界中,这是通过JIT编译器(JIT或Jitter)完成的,它是Common Language Runtime的一部分。
让我们看看它是如何工作的。您运行一个.NET应用程序。首先,CLR为所有引用类型及其方法创建一个内部数据结构。每种方法都引用将CIL编译为机器指令的过程。接下来,程序将调用一个方法。CLR看到这些方法指向抖动并启动它。编译器从元数据中读取CIL,对其进行验证,分配内存并编译字节码。然后,将对JIT编译器的引用替换为对已编译代码块的引用。最后一步是跳转到机器代码并运行它。
下次,当程序调用相同的方法时,CLR执行已编译的CPU指令。
此过程为第一个方法调用增加了一些开销。通常,您的应用程序会一遍又一遍地调用方法,并且您根本不会看到任何性能问题。
JIT将编译后的代码存储在动态内存中。这意味着,如果您同时运行两次应用程序,则将对其进行两次编译。
抖动不会在您的应用程序运行之间持久化其工作。原因是它检查您当前的系统状态(CPU类型,CPU数量等),并尝试针对当前情况生成优化的代码。下次运行应用程序时,您可能会具有不同的系统状态,并且Jitter的输出也将有所不同。
JIT类型
.NET Framework最新版本中提供了两种类型的JIT编译器。
- 普通JIT编译器。这是我上面描述的编译器。它根据需要在运行时中编译方法。
- JIT前编译器。它会在使用之前编译整个程序集。通常,编译发生在应用程序部署期间。您可以使用Ngen.exe工具(本机图像生成器).aspx)预编译程序集。
.NET Framework 1.0和1.1具有第三个JIT编译器-Econo-JIT。它是一个运行时编译器,没有进行任何优化,并且在不需要时删除了方法的机器代码。这样做是为了缩短编译时间。自.NET 2.0起,该编译器已过时,您不能再启用它。
JIT与Ngen
最后,我想比较Normal-JIT编译器和Pre-JIT编译器(Ngen)。
几乎所有情况下,普通JIT编译器都是最佳选择,因为
- 它可能会利用您当前的硬件。例如,它将使用特定于CPU的指令来实现更好的性能。
- 它将分析您的执行流程并删除未使用的循环和分支。
当应用程序可以正常工作,可以正常工作并且可以正常工作时,抖动对于服务器端应用程序肯定可以很好地工作。
Windows客户端是您可能开始考虑Ngen的唯一情况。假设您拥有庞大的Windows客户端应用程序,由于JIT编译将花费大量时间和CPU,因此可能需要很长时间才能启动。对于服务器端应用程序而言,这不是问题,但对于实际用户的软件而言,则可能是一个问题:人们不喜欢等待5分钟才能运行应用程序。
原文地址:http://geekswithblogs.net/ilich/archive/2013/07/09/.net-compilation-part-1.-just-in-time-compiler.aspx
相关文档:https://www.geeksforgeeks.org/what-is-just-in-time-jit-compiler-in-dot-net/