记录CLR JIT策略

Bre*_*ias 3 .net clr jit

我想知道CLR适用于JIT编译的范围和顺序.

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

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

似乎随着时间的推移,我发现的文章提供了一些细节的一瞥,但是现在我找不到任何能给出CLR选择JIT代码段的方式和时间的统一,可读的摘要.任何建议的书籍或链接?

如果任何这样的指南会打破.net版本的JIT决策逻辑,那将是最好的.

Bri*_*sen 6

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

假设只有被调用的方法是JIT编译的,那么对于未被调用的方法没有JIT开销.

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

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

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

    public void NotCalled()
    {
        Console.WriteLine("not called");
    }
}
Run Code Online (Sandbox Code Playgroud)

假设我们创建一个实例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()
Run Code Online (Sandbox Code Playgroud)

注意Called是JIT编译的,但是因为我们还没有调用NotCalled它,所以它还没有被JIT编译.

另外,请注意,object所有方法都是PreJIT编译的.

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