为什么.net使用JIT编译器而不是仅在目标机器上编译一次代码?

Atl*_*tli 22 .net c# jit

标题几乎总结了一下,但我想知道为什么像.net这样的系统每次运行时都会编译代码而不是仅仅在目标机器上编译一次?

Mic*_*sen 26

使用.NET或Java等中间格式可以获得两件事:

  1. 您可以在任何平台上运行该程序,因为代码是以中间格式而不是本机代码表示的.您只需要为中间格式编写解释器.
  2. 它允许一些在编译时不容易实现的运行时优化:例如,你可以利用新CPU上的特殊功能,即使你编写程序时这些CPU不存在 - 只有JIT编译器需要知道这一点.

现在,至于为什么你可能不想在第一次运行时执行编译然后只缓存它 - 这也可能有几个原因.

如果在启动之前编译,那么用户必须等待更长时间才能进行第一次运行 - 在那个时间点,您无法知道用户将实际使用的内容.通过仅编译您需要的内容,当您需要时,您可以更快地启动,因为您只需要做较少的工作,并且您不会存储许多用户永远不会使用的代码(对于大型程序可以使用是很多代码).

如果您开始跨会话缓存JIT代码,则需要跟踪已编译的内容,然后将其存储到磁盘.对于大型程序,您可能需要从磁盘加载大量本机代码.磁盘I/O非常昂贵,因此等待磁盘可能需要更长的时间而不是重新JIT它.此外,您需要跟踪缓存可用的时间.如果硬件发生更改,您可能需要重新进行JIT以应用一些新的优化.如果程序发生变化,则不能使用任何旧的编译代码.如果运行时编译器发生更改,则可能已修复了安全性错误,您需要重新编译以确保该错误不会保留在您的本机代码中.

基本上,JIT编译器突然有很多工作要做(包括处理缓存的磁盘I/O),并且变得更加复杂和缓慢,从而降低了JIT的作用.

现在,这并不意味着预编译某些程序集有时不会有利,正如Matthew Ferreira指出的那样,ngen工具可以做什么 - 但在一般情况下,它不值得这样做,因为JIT编译通常不够快.

  • 这些问题都与这个问题无关:atli询问是在目标机器上编译它,而不是在开发人员的机器上编译它. (4认同)

cdk*_*ose 6

我不编写编译器或运行时,所以我不能肯定地说这个,但我不相信每次都是及时的.它只是意味着我们要等到我们真的需要编译,但是一旦为该实例完成编译,它就不会再次编译.


Mat*_*ira 5

如果将可执行文件移动到另一台机器怎么办?如果为第一台机器的特定处理器编译了一次,它将无法利用新处理器上可用的(可能的)更高级或更有效的指令集.如果您确实想在目标计算机上编译一次,请考虑在应用程序安装期间使用ngen.exe.