2012-10-03 8 views
10

Nach meinem Verständnis werden sowohl Instanzmethoden als auch statische Methoden vom CLR-Compiler gleich behandelt und der IL-Code wird immer dann JITted, wenn die Methode das erste Mal aufgerufen wird. Heute hatte ich eine Diskussion mit meinem Kollegen und er sagte mir, dass die statischen Methoden nicht wie Instanzmethoden behandelt werden. d. h. statische Methoden werden JITted, sobald die Assembly in die Anwendungsdomäne geladen wird, während Instanzmethoden JITted sind, wie sie zum ersten Mal aufgerufen werden.Sind statische Methoden eifrig kompiliert (JIT'ed)?

Ich bin eigentlich verwirrt und sehe keinen Grund, warum die statischen Methoden eifrig von CLR kompiliert werden sollten? Ich verstehe statische Konstruktoren oder Finalizer-Methoden der Critical Finalizer-Objekte oder wenn eingeschränkte Ausführungsbereiche verwendet werden. Aber wenn eine Klasse eine Kombination aus statischen und Instanzmethoden hat, bin ich mir wirklich nicht sicher, warum alle statischen Methoden JITted wären, sobald die Assembly, die die Klasse enthält, in den Speicher geladen würde.

Bitte helfen Sie mir, dieses Verhalten zu verstehen.

+0

(Für das Protokoll wurde dieser auf 4,5 .NET getan) Ich glaube, sie würde, sobald die _type_ geladen ersten jitted werden. Dies ist normalerweise der Fall, wenn die Baugruppe geladen wird. – Oded

+0

Hat Ihr Kollege eine Referenz? Vielleicht erklärt es auch das Verhalten. Ansonsten fragst du jemanden, warum etwas passiert, das vielleicht gar nicht passiert. – millimoose

Antwort

10

Wenn man sich ansieht, wann die Methoden JIT kompiliert mit WinDbg/SOS bekommen, zeigt sich, dass statische Methoden nicht kompiliert werden, bevor sie aufgerufen werden.

Betrachten Sie die folgende Klasse:

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

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

ich die NoInlining Option die Compiler von inlining diese Methoden in einem Release-Build zu verhindern.

Wenn ich eine kleine App wie unten ausführen und den WinDbg anhängen kann ich beobachten, wenn die Methoden JIT kompiliert bekommen.

var st = new SomeType(); 

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

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

Console.ReadLine(); 

An der Stelle des Verfahrens Tisch befestigen für SomeType sieht wie folgt aus:

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

Nach den Methoden wurden aufgerufen explizit wie folgt aussieht:

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

D.h. Die Methoden werden erst dann JIT kompiliert, wenn sie tatsächlich aufgerufen werden.

+0

Ich denke, das erklärt ziemlich gut, wie und wann die Methoden JITted werden. Ich werde den Link zu diesem Q & A mit meinem Kollegen teilen. Vielen Dank für Ihre Hilfe. – jags

+0

Schöne Explorationsantwort. Erwägen Sie jedoch, CLR/.NET-Versionen hinzuzufügen, falls dies sich in der Zukunft ändert (oder nicht immer gleich war). –

1

Soweit ich weiß statische Methoden sind nicht anders als Instanzmethoden Threat, vielleicht spricht Ihr Kollege über statische Konstruktoren, die tatsächlich aufgerufen werden, sobald der Typ in der aufrufenden Assembly verwiesen wird. und so jited.

Update Für 4.0 (dank @JulienLebosquain für den Hinweis)

.NET 4.0 verwendet eine so Faul Typ Initialisierung genannt, die im Grunde das Verhalten und die Statik Konstruktor ändern aufgerufen werden nur, wenn so bald ein statischen Feld ist das erste Mal beigetreten.

+3

+1 für "nicht anders behandelt"; über statische Konstruktoren, dies ist nicht mehr wahr, siehe http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx –