Dot-Net

靜態方法是否急切地編譯(JIT’ed)?

  • October 4, 2012

根據我的理解,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");
   }
}

我使用 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()

即,在實際呼叫方法之前,它們不會被 JIT 編譯。

(作為記錄,這是在 .NET 4.5 上完成的)

引用自:https://stackoverflow.com/questions/12712541