11

私の理解では、インスタンス メソッドと静的メソッドの両方が CLR コンパイラによって同じように扱われ、メソッドが初めて呼び出されるたびに IL コードが JITted されます。今日、同僚と話し合ったところ、静的メソッドはインスタンス メソッドと同じように扱われていないとのことでした。つまり、静的メソッドは、アセンブリがアプリケーション ドメインに読み込まれるとすぐに JIT されますが、インスタンス メソッドは、最初に呼び出されたときに JIT されます。

私は実際に混乱しており、静的メソッドを CLR で積極的にコンパイルする必要がある理由がわかりません。クリティカル ファイナライザー オブジェクトの静的コンストラクターまたはファイナライザー メソッドについて、または制約付きの実行領域が使用される場合について理解しています。しかし、一部のクラスに静的メソッドとインスタンス メソッドの組み合わせがある場合、そのクラスを含むアセンブリがメモリに読み込まれるとすぐにすべての静的メソッドが JIT される理由がよくわかりません。

この動作を理解するのを手伝ってください。

4

2 に答える 2

11

メソッドが 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で行われました)

于 2012-10-03T16:22:06.840 に答える
1

私の知る限り、静的メソッドはインスタンス メソッドと同じように脅威にさらされることはありません。同僚は、呼び出し元のアセンブリで型が参照されるとすぐに実際に呼び出される静的コンストラクターについて話している可能性があります。したがって、ジッ。

4.0の更新(指摘してくれた@JulienLebosquainに感謝)

.NET 4.0 は、いわゆる Lazy Type Initialization を使用します。これにより、基本的に動作が変更され、静的フィールドが最初にアクセスされるとすぐに静的コンストラクターが呼び出されます。

于 2012-10-03T16:17:40.127 に答える