2012-10-03 30 views
10

Según entiendo, tanto los métodos de instancia como los métodos estáticos son tratados de la misma manera por el compilador CLR y el código IL está JITted cada vez que se llama al método por primera vez. Hoy tuve una conversación con mi colega y él me dijo que los métodos estáticos no se tratan de la misma manera que los métodos de instancia. es decir, los métodos estáticos están JITted tan pronto como el ensamblaje se carga en el dominio de la aplicación mientras que los métodos de la instancia están JITted cuando se los llama por primera vez.¿Los métodos estáticos se compilan con entusiasmo (JIT)?

Estoy realmente confundido y no veo una razón de por qué los métodos estáticos deben ser compilados con entusiasmo por CLR? Entiendo acerca de los constructores estáticos o los métodos de finalización de los objetos Critical Finalizer o cuando se usan regiones de ejecución restringidas. Pero si alguna clase tiene una combinación de métodos estáticos y de instancia, ¿realmente no estoy seguro de por qué todos los métodos estáticos estarían JIT tan pronto como el conjunto que contiene la clase se cargue en la memoria?

Ayúdeme a comprender este comportamiento.

+0

Me gustaría pensar que están compilados JIT tan pronto como la primera que se carga el _type_. Esto tiende a ser cuando el ensamblaje se carga. – Oded

+0

¿Su colega tiene una referencia para esto? Quizás también explica el comportamiento. De lo contrario, le estás pidiendo a alguien que explique por qué está sucediendo algo que podría no estar sucediendo. – millimoose

Respuesta

10

Al observar cuándo se compilan los métodos JIT utilizando WinDbg/SOS, se muestra que los métodos estáticos no se compilan antes de llamarlos.

Considérese la clase siguiente:

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

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

uso la opción NoInlining para evitar que el compilador de inlining estos métodos en una versión de lanzamiento.

Si ejecuto una aplicación pequeña como la que se muestra a continuación y adjunto WinDbg, puedo observar cuándo se compilan los métodos JIT.

var st = new SomeType(); 

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

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

Console.ReadLine(); 

En el momento de unir la tabla de métodos para SomeType se parece a esto:

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

Después de que los métodos han sido expresamente invocado se ve así:

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

es decir, los métodos no se compilan JIT hasta que realmente se invocan.

(Para el registro esto se hizo en .NET 4.5)

+0

Creo que esto explica muy bien cómo y cuándo se están JITted los métodos. Compartiré un enlace a esta sesión de preguntas y respuestas con mi colega. Muchas gracias por su ayuda. – jags

+0

Buena respuesta de exploración. Sin embargo, considere agregar versiones CLR/.NET utilizadas, por si acaso esto cambia en el futuro (o no siempre ha sido el mismo). –

1

Por lo que sé que los métodos estáticos no se enfrentan de manera diferente a los métodos de instancia, tal vez su colega está hablando constructores estáticos que en realidad se invocan tan pronto el tipo se refiere en el ensamblado de la llamada. y así jitted.

actualización Para 4.0 (gracias por señalar @JulienLebosquain)

.NET 4.0 utiliza un llamado Lazy Tipo de inicialización, que, básicamente, cambiar el comportamiento y la estática constructor se llama justo cuando tan pronto un campo estático se accede la primera vez.

+3

+1 para "no se trata de manera diferente"; sobre constructores estáticos, esto ya no es cierto, consulte http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx –