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

标签 .net memory-management clr jit

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

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

请帮助我理解这种行为。

最佳答案

查看何时使用 WinDbg/SOS 对方法进行 JIT 编译显示静态方法在调用它们之前没有被编译。

考虑以下类:

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

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

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

如果我运行一个像下面这样的小应用程序并附加 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 上完成的)

关于.net - 静态方法是否急切编译(JIT'ed)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12712541/

相关文章:

c# - CLR在哪里存储一种类型实例的方法

c# - 最小起订量 - 安装方法中的 LINQ 谓词

c++ - 当一个类的所有实例都被销毁时释放内存

c# - 如何避免对象分配?如何重用对象而不是分配它们?

c# - 在另一个线程中抛出异常时不调用 UnhandledException

c# - 获取 "belong"到当前文化的字符列表

c# - UPS API .net 无法解析命名空间 TrackWSSample.TrackWebReference

oracle - 解决ORA-4031 “unable to allocate x bytes of shared memory”

c# - 我们可以在 DotNet 类库项目中使用 global.asax 文件吗

sql-server - 在具有可变列数的 T-SQL 返回表中具有表值函数