2013-02-12 62 views
3

我想知道CLR适用于JIT编译的范围和顺序。记录CLR JIT策略

例如,如果我的应用程序只调用给定类的单个方法,那么该类的未使用方法是否会无用地编译JIT?如果是的话,在执行我需要的一种方法之前它们都是JIT编译的,还是在事实之后被懒惰地编译?

那么方法中的分支呢? CLR是否允许编译一个方法中的一半代码,同时允许同一方法中的单独分支在需要时保持未编译状态?

看来随着时间的推移,我发现了一些文章,提供了一些这些细节的一瞥,但现在我没有找到任何提供整合,可读的CLR如何以及何时选择JIT一节的代码。任何建议的书籍或链接?

如果任何这样的指南将通过.net版本分解这样的JIT决策逻辑,那将是最好的。

回答

6

JIT在.NET中的工作方式是,在方法被调用之前,方法表入口指向一个小的存根,当被调用时将会调用该方法。之后,方法表被更新以引用JIT编译代码的位置。

鉴于只有被调用的方法是JIT编译的,没有调用的方法没有JIT开销。

JIT编译器将在需要时编译整个方法。如果它是一个发布版本,代码可能会被优化掉,否则该方法会被完全编译。

您可以使用WinDbg/SOS检查方法表。考虑以下几点:

class SomeType 
{ 
    public void Called() 
    { 
     Console.WriteLine("called"); 
    } 

    public void NotCalled() 
    { 
     Console.WriteLine("not called"); 
    } 
} 

假设我们创建的SomeType实例,调用Called然后检查方法表SomeType。在x86上,你会看到这样的内容:

0:000> !dumpmt -md 00a7381c 
EEClass:   00a712d0 
Module:   00a72e94 
Name:   ConsoleApplication1.SomeType 
mdToken:   02000002 
File:   c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe 
BaseSize:  0xc 
ComponentSize: 0x0 
Slots in VTable: 7 
Number of IFaces in IFaceMap: 0 
-------------------------------------- 
MethodDesc Table 
    Entry MethodDe JIT Name 
72ca4960 729a6728 PreJIT System.Object.ToString() 
72c98790 729a6730 PreJIT System.Object.Equals(System.Object) 
72c98360 729a6750 PreJIT System.Object.GetHashCode() 
72c916f0 729a6764 PreJIT System.Object.Finalize() 
00df00d8 00a73814 JIT ConsoleApplication1.SomeType..ctor() 
00df0110 00a737fc JIT ConsoleApplication1.SomeType.Called() 
00a7c031 00a73808 NONE ConsoleApplication1.SomeType.NotCalled() 

注意Called是JIT编译的,但我们还没有调用NotCalled的是,它并没有被JIT编译。

此外,请注意,从object所有的方法都已被PreJIT编译。

请记住,在发布版本中,可能会内联简短方法,在这种情况下,它们不会被称为方法,而只是作为调用站点的生成代码的一部分。