是否急切地编译静态方法(JIT'ed)?

jag*_*ags 10 .net clr jit memory-management

根据我的理解,CLR编译器对实例方法和静态方法都采用相同的方法,只要第一次调用该方法,IL代码就是JITted.今天我和我的同事进行了讨论,他告诉我静态方法的处理方式与实例方法不同.即,只要程序集加载到应用程序域中,静态方法就会被JIT,而实例方法在第一次被调用时就会被JIT.

我真的很困惑,并没有看到为什么静态方法应该由CLR急切编译的原因?我理解关键终结器对象的静态构造函数或终结器方法,或者使用约束执行区域时.但是如果某个类有静态方法和实例方法的组合,我真的不确定为什么一旦包含该类的程序集被加载到内存中,所有静态方法都会被JIT实现?

请帮助我理解这种行为.

Bri*_*sen 10

查看方法何时使用WinDbg/SOS编译JIT表明静态方法在调用之前未编译.

考虑以下课程:

class SomeType
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    public void InstanceMethod()
    {
        Console.WriteLine("instance");
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void TypeMethod()
    {
        Console.WriteLine("type");
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用NoInlining选项来阻止编译器在发布版本中内联这些方法.

如果我运行如下的小应用程序并附加WinDbg,我可以观察方法何时获得JIT编译.

var st = new SomeType();

Console.WriteLine("attach");
Console.ReadLine();

Console.WriteLine("calling methods");
st.InstanceMethod();
SomeType.TypeMethod();

Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

在附加方法表时,SomeType看起来像这样:

0:004> !dumpmt -md 0041387c
EEClass:         004114d4
Module:          00412e94
Name:            ConsoleApplication2.SomeType
mdToken:         02000007
File:                c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
   Entry MethodDe    JIT Name
6d374960 6d076728 PreJIT System.Object.ToString()
6d368790 6d076730 PreJIT System.Object.Equals(System.Object)
6d368360 6d076750 PreJIT System.Object.GetHashCode()
6d3616f0 6d076764 PreJIT System.Object.Finalize()
0041c035 00413874   NONE ConsoleApplication2.SomeType..ctor()
0041c02d 0041385c   NONE ConsoleApplication2.SomeType.InstanceMethod()
0041c031 00413868   NONE ConsoleApplication2.SomeType.TypeMethod()
Run Code Online (Sandbox Code Playgroud)

显式调用方法后,它看起来像这样:

0:007> !dumpmt -md 0041387c
EEClass:         004114d4
Module:          00412e94
Name:            ConsoleApplication2.SomeType
mdToken:         02000007
File:            c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
   Entry MethodDe    JIT Name
6d374960 6d076728 PreJIT System.Object.ToString()
6d368790 6d076730 PreJIT System.Object.Equals(System.Object)
6d368360 6d076750 PreJIT System.Object.GetHashCode()
6d3616f0 6d076764 PreJIT System.Object.Finalize()
0041c035 00413874   NONE ConsoleApplication2.SomeType..ctor()
004700e0 0041385c    JIT ConsoleApplication2.SomeType.InstanceMethod()
00470110 00413868    JIT ConsoleApplication2.SomeType.TypeMethod()
Run Code Online (Sandbox Code Playgroud)

即在实际调用它们之前,方法不是JIT编译的.

(记录这是在.NET 4.5上完成的)