静态方法是否会立即编译(JIT)?

2024-05-08

根据我的理解,CLR 编译器对实例方法和静态方法的处理方式相同,并且每当首次调用该方法时,IL 代码都会进行 JIT 编译。今天我和同事讨论了,他告诉我静态方法与实例方法的处理方式不同。即,静态方法在程序集加载到应用程序域后立即进行 JIT 处理,而实例方法在第一次调用时进行 JIT 处理。

我实际上很困惑,不明白为什么 CLR 应该急切地编译静态方法?我了解关键终结器对象的静态构造函数或终结器方法,或者何时使用约束执行区域。但是,如果某个类具有静态方法和实例方法的组合,我真的不确定为什么一旦包含该类的程序集被加载到内存中,所有静态方法都会被 JITted?

请帮助我理解这种行为。


查看使用 WinDbg/SOS 何时对方法进行 JIT 编译表明,静态方法在调用之前不会进行编译。

考虑下面的类:

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

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void TypeMethod()
    {
        Console.WriteLine("type");
    }
}

我使用 NoInlined 选项来防止编译器在发布版本中内联这些方法。

如果我运行一个如下所示的小应用程序并附加 WinDbg,我可以观察方法何时进行 JIT 编译。

var st = new SomeType();

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

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

Console.ReadLine();

附上方法表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()

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

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()

IE。这些方法在实际调用之前不会进行 JIT 编译。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

静态方法是否会立即编译(JIT)? 的相关文章

随机推荐