.NET CLR JIT每次都编译每个方法吗?

时间:2009-08-10 16:14:39

标签: .net clr jit

我知道Java的HotSpot JIT有时会跳过JIT编译方法,如果它希望编译的开销低于在解释模式下运行方法的开销。 .NET CLR是否基于类似的启发式工作?

4 个答案:

答案 0 :(得分:44)

注意:这个答案是在“每次运行”的上下文中。每次运行程序时,代码通常都是JIT。使用ngen.NET Native也会改变这个故事......

与HotSpot不同,CLR JIT每次运行总是编译完全。它永远不会解释,并且它永远不会根据实际使用情况进行比以前更重的优化。

当然,这可能会有所改变,但是自从v1开始以来我就不会这样了,我不希望它会在短期内发生变化。

优势在于它使JIT变得更加简单 - 不需要考虑已经运行的“旧”代码,基于不再有效的前提撤消优化等。

.NET的一个优点是大多数CLR语言默认情况下使方法非虚拟,这意味着可以完成更多的内联。 HotSpot可以内联一个方法,直到它被第一次覆盖,此时它会撤消优化(或者在某些情况下做一些聪明的东西,有条件地仍然使用内联代码,基于实际类型)。由于需要担心的虚拟方法较少,.NET可以在很大程度上忽略无法内联任何虚拟内容的痛苦。

编辑:以上描述了桌面框架。 Compact Framework在需要时抛出本机代码,必要时再次进行JITting。但是,这仍然不像HotSpots自适应优化。

微框架显然没有JIT,而是解释代码。这对于非常受约束的设备是有意义的。 (我不能说我对微框架了解很多。)

答案 1 :(得分:14)

.NET运行时总是在执行之前编译代码JIT。所以,它永远不会被解释。

您可以使用CLR Design Choices Anders Hejlsberg 中找到更有趣的阅读材料。特别是部分:

  

我读到微软决定永远编译IL,从不解释。指令中的编码类型信息如何帮助解释器更有效地运行?

     

Anders Hejlsberg:如果翻译人员可以盲目地执行指令所说的而不需要跟踪堆栈顶部的内容,那么它可以更快。例如,当它看到iadd时,解释器首先不必弄清楚它是哪种添加,它知道它是一个整数加法。假设有人已经确认堆栈看起来是正确的,那么在那里减少一些时间是安全的,并且你关心那个解释器。但在我们的例子中,我们从未打算用CLR来解释解释的场景。我们打算始终JIT [Just-in-time compile],为了JIT的目的,我们还需要跟踪类型信息。由于我们已经有了类型信息,因此它实际上并没有给我们任何东西以便将它放在说明书中。

     Bill Venners:许多现代JVM [Java虚拟机]都进行自适应优化,他们从解释字节码开始。他们在运行时对应用程序进行概要分析,以找到80%到90%执行时代码的10%到20%,然后将它们编译为本机代码。但是,它们不一定只是及时编译那些字节码。方法的字节码仍然可以由解释器执行,因为它们被编译为本机并在后台进行优化。当本机代码准备就绪时,它可以替换字节码。通过不针对解释的场景,您是否完全排除了在CLR中执行的方法?

     

Anders Hejlsberg:不,我们还没有完全排除这一点。我们仍然可以解释。我们还没有针对口译进行优化。我们没有优化编写那些只能解释的最高性能解释器。我认为没有人再这样做了。对于10年前的机顶盒来说,这可能很有趣。但它不再有趣。 JIT技术已经达到了可以有多种可能的JIT策略的程度。您甚至可以想象使用快速跳过的快速JIT,然后当我们发现我们一直在执行特定方法时,使用另一个花费更多时间并更好地优化的JIT。你可以做更多JIT明智的事情。

答案 2 :(得分:3)

对于内存较低的设备,将来会看到一些基于跟踪的JIT会很高兴。它主要解释,找到热点,并将它们转换为汇编程序并缓存它们。我认为Google就是他们的Android JIT所做的事情,Microsoft Research正在为基于跟踪的JIT进行研究项目。

我发现了一篇文章, SPUR: A Trace-Based JIT Compiler for CIL ..也许其中一些文章有一天会进入CLR

答案 3 :(得分:0)

我不相信,我认为不应该这样。

JIT如何知道调用特定方法的次数?难道解释的频率不会影响决策吗?

我还会质疑JIT编译器能够分析函数以确定在不解释函数本身的情况下解释是否最佳。鉴于这个事实(至少已经发生了一次方法),简单地编译每个方法以减少尝试确定哪些方法首先被编译的开销不是更好吗?