Старые методы с готовностью компилируются (JIT'ed)?

В моем понимании, как методы экземпляра, так и статические методы обрабатываются одним и тем же компилятором CLR, а код IL - JIT, когда метод вызывается в первый раз. Сегодня у меня была дискуссия с моим коллегой, и он сказал мне, что статические методы не обрабатываются так же, как методы экземпляра. т.е. статические методы JIT, как только сборка загружается в область приложения, тогда как методы экземпляра JIT, так как они вызываются в первый раз.

Я действительно запутался и не вижу причины, почему статические методы должны с готовностью собираться с помощью CLR? Я понимаю о статических конструкторах или методах финализатора объектов Critical Finalizer или при использовании областей с ограниченным исполнением. Но если какой-то класс имеет комбинацию статических и экземплярных методов, я действительно не уверен, почему все статические методы будут JIT, как только сборка, содержащая класс, будет загружена в память?

Пожалуйста, помогите мне в понимании этого поведения.

Ответ 1

Посмотрев, когда методы получают JIT, скомпилированные с использованием WinDbg/SOS, показано, что статические методы не компилируются до их вызова.

Рассмотрим следующий класс:

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)

Ответ 2

Насколько я знаю, статические методы не обрабатываются иначе, чем методы экземпляра, возможно, ваш коллега говорит о статических конструкторах, которые фактически вызывается, как только тип передается в вызывающей сборке. и, таким образом, дрожат.

Обновить для 4.0 (спасибо @JulienLebosquain за указание)

В .NET 4.0 используется так называемая инициализация Lazy Type, которая в основном меняет поведение, а конструктор statics вызывается только тогда, когда в первый раз присоединяется поле static.