Может ли соответствующий компилятор С# оптимизировать локальную (но неиспользуемую) переменную, если это единственная сильная ссылка на объект?

См. также эти связанные ресурсы:


Другими словами:

Может ли объект, на который ссылается локальный переменная должна быть исправлена ​​до переменная выходит за рамки (например. потому что переменная назначена, но затем не используется снова), или это объект гарантированно не подлежит сбор мусора до тех пор, пока переменная выходит за рамки?

Позвольте мне объяснить:


void Case_1()
{
    var weakRef = new WeakReference(new object());

    GC.Collect();  // <-- doesn't have to be an explicit call; just assume that
                   //     garbage collection would occur at this point.

    if (weakRef.IsAlive) ...
}

В этом примере кода я, очевидно, должен планировать возможность того, что новый object будет возвращен сборщиком мусора; поэтому оператор if.

(Обратите внимание, что я использую weakRef с единственной целью проверить, находится ли новый object.)


void Case_2()
{
    var unusedLocalVar = new object();
    var weakRef = new WeakReference(unusedLocalVar);

    GC.Collect();  // <-- doesn't have to be an explicit call; just assume that
                   //     garbage collection would occur at this point.

    Debug.Assert(weakRef.IsAlive);
}

Основное изменение в этом примере кода из предыдущего состоит в том, что новый object сильно ссылается на локальную переменную (unusedLocalVar). Однако эта переменная никогда не используется снова после того, как была создана слабая ссылка (weakRef).


Вопрос:. Соответствующий С# -компилятор разрешил оптимизировать первые две строки Case_2 по сравнению с Case_1, если видит, что unusedLocalVar используется только в одном месте, а именно: аргумент конструктору WeakReference? т.е. существует ли вероятность того, что утверждение в Case_2 могло бы потерпеть неудачу?

Ответ 1

Не имеет значения, что делает компилятор С# - JITTER/GC разрешено очищать локальные ссылки, когда они больше не живы в теле метода. Посмотрите на документы для GC.KeepAlive

Кроме того, эта презентация PowerPoint, особенно с слайда 30 и далее, помогает объяснить, что может сделать JIT/GC.

Ответ 2

В то время как на мой вопрос был дан ответ, я думал, что опубликую эту важную часть информации, которую я только что нашел в статье блога MSDN "WP7: Когда GC Рассмотрим локальную переменную как мусор" abhinaba:

[T] спецификация ECMA (ECMA 334, раздел 10.9) [& hellip;] states

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

Это все говорит. В упомянутой статье также говорится, что платформа .NET(по крайней мере, в режиме Release) будет выполнять интеллектуальный анализ и освобождать такие объекты, в то время как .NET Compact Framework не будет (по соображениям производительности).

Ответ 3

Согласован ли компилятор С#, позволяющий оптимизировать первые две строки Case_2 по сравнению с Case_1, если он видит, что unusedLocalVar используется только в одном месте, а именно в качестве аргумента конструктору WeakReference?

Два определения эквивалентны, поэтому переход от одного к другому не является "оптимизацией", потому что ни один из них не является более эффективным.

то есть. есть ли вероятность того, что утверждение в Case_2 может не получиться?

Да. Производственный компилятор вряд ли сохранит ссылку без необходимости, поэтому он будет удален, GC не увидит его как глобальный root и соберет этот объект.

Обратите внимание, что сборщики мусора не видят вашу программу с точки зрения переменных и объема. Эти концепции высокого уровня уже давно скомпилированы к тому моменту, когда ваш код попадает в сборщик мусора. GC видит только регистры, стеки потоков и глобальные переменные.