Анализ побега в .NET CLR VM - PullRequest
       53

Анализ побега в .NET CLR VM

14 голосов
/ 22 ноября 2011

Есть ли какой-либо escape-анализ, выполняемый компилятором / JIT CLR? Например, в Java кажется, что переменная цикла объект, размещенный в цикле, который не выходит из цикла, размещается в стеке, а не в куче (см. Анализ побега в Java ).

Чтобы пояснить, в примере ниже, будет ли компилятор оптимизировать выделение кучи foo, поскольку он никогда не выходит из цикла.

class Foo 
{ 
   int number;
   Foo(int number) { this.number = number; }
   public override string ToString() { return number.ToString(); }
}

for (int i = 0; i < 10000000; i++)
{
   Foo foo = new Foo(i);
   Console.WriteLine(foo.ToString());
}

Ответы [ 3 ]

12 голосов
/ 22 ноября 2011

Если вы имеете в виду объект (new Foo(i);), то я понимаю, что нет: это никогда не выделяется в стеке;однако, он умрет в нулевом поколении, поэтому будет очень эффективным для сбора.Я не признаю, что знаю каждый темный и сырой угол CLI, но я не знаю ни одного сценария в C # , который привел бы к тому, что управляемый ссылочный тип был бы выделен в стеке (такие вещи, как stackalloc на самом деле не считается и очень специфичен).Очевидно, что в C ++ у вас есть еще несколько опций, но тогда это не управляемый экземпляр.

Интересно, что в MonoTouch / AOT это может быть собрано немедленно , но это не основнойВиртуальная машина CLI (и для очень специфического сценария).

Что касается переменной , то будет обычно находиться в стеке (и повторно использоваться для каждого циклаитерация) - но это может не быть .Например, если это «блок итератора», то все не удаленные локальные переменные фактически являются полями конечного автомата, созданного компилятором.Чаще всего, если переменная «захвачена» (в анонимный метод или лямбда-выражение, оба из которых образуют замыкания), тогда переменная преобразуется в поле сгенерированного компилятором контекста захвата, и является отдельным для каждой итерации цикла (так как foo объявлено внутри цикла).Это означает, что каждый из них - отдельный в куче.

Что касается i (переменная цикла) - если , что захвачено, это становится еще более интересным

  • в C # 1.2 захватов не существовало, но по спецификации переменная цикла равна технически на одну итерацию
  • в C # от 2.0 до 4.0, циклпеременная является общей (вызывая печально известный общий вопрос захвата / foreach)
  • в C # 5.0 и выше, переменная цикла снова является повторной для каждой итерации

это имеет значение только тогда, когда переменнаязахватывается, но меняет семантику точно как это проявляется в контексте захвата

5 голосов
/ 22 ноября 2011

Тип значения может быть выделен в стеке (не всегда), но это не относится к экземплярам ссылочных типов.Фактически:

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

(Эрик Липперт: Правда о типах значений )

Также Стек - деталь реализации хорошо читает.

1 голос
/ 22 ноября 2011

Несмотря на то, что x86 JIT хорош для «встраивания» значений типов, ваш фрагмент не будет квалифицирован, так как метод ToString будет виртуальным вызовом объекта в штучной упаковке. Редактировать: Это может быть не так, поскольку вы не переопределяете ToString.

x64 JIT, однако, не делает этого вообще из моих экспериментов.

Edit:

Если возможно, протестируйте код на x86 и x64.

...