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

jsi*_*ght 26 .net clr jit

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

Jon*_*eet 44

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

不像热点,CLR的JIT编译总是恰好每运行一次.它永远不会解释,它永远不会根据实际使用情况重新编译比以前更重的优化.

当然,这可能会改变,但是自从v1以来我就不会这样了,我不希望它会很快改变.

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

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

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

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

  • 桌面CLR不会抛出(卸载)jitted代码,因此它只编译一次方法..NET Compact Framework中的CLR可以在需要时再调整代码并重新设置它,以适应紧凑型CLR运行的资源受限的环境. (5认同)
  • 我不相信它实际上解释了代码 - 调试器能够适当地逐步完成编译代码,这就是全部.Mono*确实*有翻译. (4认同)
  • 奇怪的是,.net MF(嵌入式设备的MicroFramework)确实解释了IL而不是编译它. (2认同)

Dej*_*nič 14

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

你可以找到一些更有趣的阅读CLR设计选择安德斯·海尔斯伯格.特别是部分:

我读到微软决定永远编译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智慧.