即时编译与提前编译有什么好处?

zne*_*eak 68 jit compilation

我最近一直在考虑这个问题,在我看来,JIT编译的大多数优点应该或多或少地归结为中间格式,并且jints本身并不是生成代码的好方法.

所以这些是我经常听到的主要的JIT编译参数:

  1. 即时编译可实现更高的可移植性.这不是因为中间格式吗?我的意思是,一旦你的虚拟字节码在你的机器上得到它,没有什么能阻止你将它们编译成本机字节码.可移植性是"分发"阶段的问题,而不是"运行"阶段.
  2. 那么,那么在运行时生成代码呢?嗯,同样适用.没有什么可以阻止您将实时编译器集成到您的本机程序中以实现真正的及时需求.
  3. 但运行时只需将其编译为本机代码一次,并将生成的可执行文件存储在硬盘驱动器上某处的某种缓存中.当然可以.但它在时间限制下优化了你的程序,而且从那时起它并没有让它变得更好.见下一段.

它不像提前编译也没有优势.即时编译有时间限制:在程序启动时,您不能让最终用户永远等待,因此需要权衡某些事情.大多数时候他们只是减少优化.我的一个朋友有分析证据表明内联函数和"手动"展开循环(在过程中混淆源代码)对他的C#号码运算程序的性能产生了积极影响; 在我这方面做同样的事情,我的C程序填写相同的任务,没有产生任何积极的结果,我相信这是由于我的编译器允许进行广泛的转换.

然而,我们被jitted程序包围.C#Java无处不在,Python脚本可以编译成某种字节码,我确信其他一些编程语言也是如此.我必须有一个很好的理由让我失踪.那么什么使即时编译如此优于提前编译?


编辑为了清除一些混淆,也许重要的是要声明我全都是可执行文件的中间表示.这有很多优点(实际上,实时编译的大多数参数实际上是中间表示的参数).我的问题是如何将它们编译为本机代码.

大多数运行时(或编译器)都倾向于及时或提前编译它们.由于编译器有更多的时间来执行优化,因此提前编译看起来像是一个更好的替代方案,我想知道为什么微软,Sun和所有其他人都在反过来.我对与分析相关的优化有点怀疑,因为我对即时编译程序的经验表现出很差的基本优化.

我用了一个例子与C语言代码,只是因为我需要的例子名列前茅的时间编制与刚刚在时间编译.C代码没有发送到中间表示的事实与情况无关,因为我只需要表明提前编译可以产生更好的即时结果.

Thi*_*ilo 34

  1. 更高的可移植性:可交付成果(字节码)保持可移植性

  2. 同时,更具体的平台:因为JIT编译发生在代码运行的同一系统上,所以它可以针对特定系统进行非常非常精细的调整.如果您提前进行编译(并且仍然希望将相同的包发送给每个人),则必须妥协.

  3. 编译器技术的改进可能会对现有程序产生影响.一个更好的C编译器根本没有帮助您使用已部署的程序.更好的JIT编译器将提高现有程序的性能.你十年前写的Java代码今天运行得更快.

  4. 适应运行时指标.JIT编译器不仅可以查看代码和目标系统,还可以查看代码的使用方式.它可以检测正在运行的代码,并根据例如方法参数通常碰巧具有的值来决定如何优化.

你是对的JIT增加了启动成本,所以它有一个时间限制,而提前编译可以花费它想要的所有时间.这使得它更适合服务器类型的应用程序,其中启动时间不是那么重要,并且在代码变得非常快之前的"预热阶段"是可接受的.

我想可以在某处存储JIT编译的结果,以便下次可以重用它.这将为您提供第二个程序运行的"提前"编译.也许Sun和微软的聪明人都认为新的JIT已经足够好了,额外的复杂性不值得麻烦.

  • 对于你的第一点和第二点,如果我只是在安装过程中使用字节码并在最终用户的机器上为他的特定系统提前编译了怎么办?这就是为什么我说这些优点是相对于中间格式而不是即时编译.至于你的第三点,是的,我想这是真的.但是,如果我的本机代码现在运行速度是我现在运行的jitted代码的两倍,那么10年后我对它的性能不太感兴趣. (10认同)
  • @Anon:应该说明即时编译和提前编译的要求是相同的.没有.NET框架就无法运行.NET程序,因此虚拟机已经破坏了可移植性. (9认同)
  • 对不起,这是个坏死的事.看看JIT生成(优化)的.NET机器代码,我不得不说你的第2,3和4点都是无效的..NET JIT几乎没有任何明显的微调,生成的机器代码明显较差(与未经优化的C++机器代码相当).10年前在C中生成的代码即使在今天仍然会更快.最后,任何运行时指标都没有影响.即使在运行或"预热"功能100,000次之后,.NET JIT也不会对代码进行任何更改.再次,对不起,但我觉得必须对此进行评论. (4认同)
  • 非常抱歉,10年过去了。有人关心评估关于 JIT 编译器进步提高旧程序性能的说法是否属实吗? (2认同)

zne*_*eak 15

The ngen tool page spilled the beans (or at least provided a good comparison of native images versus JIT-compiled images). Executables that are compiled ahead-of-time typically have the following benefits:

  1. Native images load faster because they don't have much startup activities, and require a static amount of fewer memory (the memory required by the JIT compiler);
  2. Native images can share library code, while JIT-compiled images cannot.

Just-in-time compiled executables typically have the upper hand in these cases:

  1. Native images are larger than their bytecode counterpart;
  2. Native images must be regenerated whenever the original assembly or one of its dependencies is modified.

The need to regenerate an image that is ahead-of-time compiled every time one of its components is a huge disadvantage for native images. On the other hand, the fact that JIT-compiled images can't share library code can cause a serious memory hit. The operating system can load any native library at one physical location and share the immutable parts of it with every process that wants to use it, leading to significant memory savings, especially with system frameworks that virtually every program uses. (I imagine that this is somewhat offset by the fact that JIT-compiled programs only compile what they actually use.)

The general consideration of Microsoft on the matter is that large applications typically benefit from being compiled ahead-of-time, while small ones generally don't.


vav*_*ava 6

简单的逻辑告诉我们,即使从字节码编译巨大的MS Office大小程序也只需要花费太多时间.你最终会有很长的开始时间,这会吓到你的产品.当然,您可以在安装期间进行预编译,但这也会产生后果.

另一个原因是并非所有应用部分都会被使用.JIT将仅编译用户关心的那些部分,可能会使80%的代码保持不变,从而节省时间和内存.

最后,JIT编译可以应用普通编译器无法实现的优化.像使用跟踪树内联虚拟方法或方法的一部分.从理论上讲,这可以使它们更快.

  • +1.有一点是说"如果你不反复运行一个子程序,为什么你需要它快速(并花时间让它快速)?" 当然,这是假设如果你经常运行它,JIT会非常快.这可能不会在第一轮编译中发生,但最终...... (6认同)
  • **当然,你可以在安装过程中进行预编译,但这也有后果。**有什么后果??是不是安装很慢?所有安装都很慢,让更快的应用程序变得有点慢,这对我来说似乎没有什么后果。 (3认同)
  • 我没有得到你的第一个论点.是应该反对即时编译还是反对提前编译?在内存节省和时间方面,编译未触及的程序部分浪费的时间只浪费了一次,所以这并不是一个很好的IMO.如果将整个虚拟字节码加载到内存中,它就不会节省太多内存. (2认同)

dsi*_*cha 5

  1. 更好的反射支持。原则上这可以在提前编译的程序中完成,但在实践中似乎从未发生过。

  2. 通常只能通过动态观察程序才能找出优化。例如,内联虚拟函数、将堆栈分配转换为堆分配的逃逸分析以及锁粗化。

  • 事实上,您的程序在运行之前会被编译为本机代码。因此,即使对于本机程序,反射显然也是可能的,这更多的是运行时的问题,而不是编译方式的问题。至于逃逸分析,我认为基于运行时观察而不是静态代码分析是一个糟糕的想法。 (2认同)