标题几乎总结了一下,但我想知道为什么像.net这样的系统每次运行时都会编译代码,而不是只在目标机器上编译一次?
答案 0 :(得分:25)
使用.NET或Java等中间格式可以获得两件事:
现在,至于为什么你可能不想在第一次运行时执行编译然后只是缓存它 - 这也可能有几个原因。
如果你在启动之前编译,那么用户必须等待很长时间才能进行第一次运行 - 在那个时间点,你无法知道用户将实际使用什么。通过只编译你需要的东西,当你需要它时,你可以更快地开始,只是因为你没有多少工作要做,而且你没有存储很多用户永远不会使用的代码(对于大型程序可以是很多代码。)
如果您开始跨会话缓存JIT代码,则需要跟踪已编译的内容然后将其存储到磁盘。对于大型程序,您可能需要从磁盘加载大量本机代码。磁盘I / O非常昂贵,因此等待磁盘可能需要更长的时间而不是重新JIT它。此外,您需要跟踪缓存可用的时间。如果硬件发生更改,您可能需要重新进行JIT以应用一些新的优化。如果程序发生变化,则不能使用任何旧的编译代码。如果运行时编译器发生更改,则可能已修复了安全漏洞,您需要重新编译以确保该漏洞不会保留在您的本机代码中。
基本上,JIT编译器突然有很多工作要做(包括用于处理缓存的磁盘I / O),并且变得更加复杂和缓慢,从而降低了JIT的作用。
现在,这并不意味着预编译某些程序集有时不会有利,正如Matthew Ferreira指出的那样,ngen工具可以做什么 - 但在一般情况下,它只是不值得这样做,因为JIT编译通常足够快。
答案 1 :(得分:6)
我不编写编译器或运行时,所以我不能肯定地说这个,但我不相信每次都是及时的。它只是意味着我们要等到我们真的需要编译,但是一旦为该实例完成编译,它就不会再次编译。
答案 2 :(得分:5)
如果将可执行文件移动到另一台计算机怎么办?如果为第一台机器的特定处理器编译了一次,它将无法利用新处理器上可用的(可能的)更高级或更有效的指令集。如果您真的想在目标计算机上编译一次,请考虑在应用程序安装期间使用ngen.exe。
答案 3 :(得分:3)
JIT编译的另一个优点:10年或15年前编写的代码可以通过使用最先进的JIT运行来获得显着的性能提升,而不需要对代码进行任何更改。
答案 4 :(得分:2)
标题几乎总结了一下,但我想知道为什么像.net这样的系统每次运行时都会编译代码,而不是只在目标机器上编译一次?
.NET会将CIL的编译结果缓存到给定目标上的本机代码,但这并非易事:
System.Reflection.Emit
的使用,还包括动态加载的程序集中的类型的统一,甚至在多态递归期间创建新的值类型。答案 5 :(得分:0)
如果您直接编译为机器代码,那么您已针对特定系统:
Code --> Machine Code
但是,在.NET,Java等中,您所针对的是虚拟机。这将生成任何符合.NET的VM可以解释的代码,并依次将JIT转换为真实的机器代码。
所以,在.NET中:
Code --> IL --> VM (executing) --> JIT'd Machine Code
最初它看起来更复杂,但考虑针对多种架构:
Code(x86) --> Machine Code(x86) Code(ppc) --> Machine Code(ppc) etc... (1x code-set per target)
对战
Code --> IL --> VM(x86) (executing) --> JIT'd x86 Machine Code VM(ppc) (executing) --> JIT'd ppc Machine Code etc...
我的插图很粗略,但你会注意到一个.NET代码包可以在多个平台上定位和运行