Под что выделится новая память в компилированной лямбде?

Допустим есть метод. Под что в данном примере выделится память?

class C 
{
   public void Method()
   {
      Task.Run(() => { });
   }
}

В Release компилятор сделает следующую структуру:

public class C
{
    [Serializable]
    [CompilerGenerated]
    private sealed class <>c
    {
        public static readonly <>c <>9 = new <>c();

        public static Action <>9__0_0;

        internal void <M>b__0_0()
        {
        }
    }

    public void M()
    {
        Task.Run(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Action(<>c.<>9.<M>b__0_0)));
    }
}

Получается, что в классе <>c создается поле <>c <>9 = new <>c() для того, чтобы обратиться к методу <M>b__0_0. Я так полагаю доп. память выделяется только <>9.

Ведь если не использовать лямбу:

public class C 
{
    public void M() 
    {
        Task.Run(new Action(A));
    }
    void A() {}
}

То компилируется это в то же самое и память соответственно выделяется только под new Action() (в первом случае у нас еще и инициализация поля <>9).


Ответы (1 шт):

Автор решения: aepot

Очевидно же, лямбда изолируется в самостоятельном объекте, если не считать нестатические члены, то в нем ничего нет, поэтому расход памяти будет равен минимальному размеру объекта в памяти, 24 байта для x64 и 12 байт для x86, насколько я помню. Память под две статические ссылки - 16 или 8 байт соответственно будет выделена при запуске приложения.

Объект, как видно, будет создан однократно на всё время работы приложения. Поэтому расход процессорного времени и памяти на создание объекта будет произведен однократно, а впоследствии объект будет переиспользован.

Есть кстати неплохая статья на Хабре на эту тему.

→ Ссылка