Are static methods eagerly compiled (JIT'ed)?

2019-03-18 18:21发布

问题:

Per my understanding, both instance methods and static methods are treated same by CLR compiler and the IL code is JITted whenever the method is called first time. Today I had a discussion with my colleague and he told me that the static methods are not treated the same way as instance methods. i.e. Static methods are JITted as soon as the assembly is loaded into application domain whereas instance methods are JITted as they are called for the first time.

I am actually confused and do not see a reason as to why the static methods should be eagerly compiled by CLR? I understand about static constructors or finalizer methods of the Critical Finalizer Objects or when constrained execution regions are used. But if some class has a combination of static and instance methods, I am really not sure why all static methods would be JITted as soon as the assembly containing the class would be loaded into memory?

Please help me in understanding this behavior.

回答1:

Looking at when the methods get JIT compiled using WinDbg/SOS shows that static methods are not compiled prior to calling them.

Consider the following class:

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

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

I use the NoInlining option to prevent the compiler from inlining these methods in a release build.

If I run a small app like below and attach the WinDbg I can observe when the methods get JIT compiled.

var st = new SomeType();

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

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

Console.ReadLine();

At the point of attach the method table for SomeType looks like this:

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

After the methods have been explicitly invoked it looks like this:

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

I.e. the methods are not JIT compiled until they are actually invoked.

(For the record this was done on .NET 4.5)



回答2:

As far as I know static methods are not threated differently from instance methods, maybe your colleague is talking about static constructors that actually are invoked as soon the type is referred in the calling assembly. and thus jitted.

Update For 4.0 ( thanks @JulienLebosquain for pointing )

.NET 4.0 uses a so called Lazy Type Initialization, that basically change the behavior and statics constructor are called just when as soon a static field is acceded the first time.