符合条件的C#编译器是否可以优化本地(但未使用)变量(如果它是对象的唯一强引用)?

sta*_*ica 11 .net c# garbage-collection weak-references compiler-optimization

另见这些相关资源:


换一种说法:

可以在变量超出范围之前回收局部变量引用的对象(例如,因为变量已分配,但之后不再使用),或者该变量在变量退出之前保证不符合垃圾收集条件.范围?

让我解释:


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) ...
}
Run Code Online (Sandbox Code Playgroud)

在这个代码示例中,我显然必须计划object垃圾收集器回收new'ed的可能性; 因此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);
}
Run Code Online (Sandbox Code Playgroud)

这个代码示例与前一个代码示例的主要变化是new'ed object被局部变量(unusedLocalVar)强烈引用.但是,weakRef在创建弱引用()之后,永远不会再次使用此变量.


问:是标准的C#编译器允许前两行的优化Case_2到这些的Case_1,如果它看到的是unusedLocalVar只在一个地方使用,即作为参数传递给WeakReference构造函数?即,断言是否有可能Case_2失败?

Dam*_*ver 12

C#编译器的作用并不重要 - 一旦它们在方法体中不再存在,JITter/GC就可以清理它们.查看GC.KeepAlive的文档

此外,这个powerpoint演示文稿,特别是从幻灯片30开始,有助于解释JIT/GC可以达到的目的.

  • 另请注意,在调试版本中,变量显式保持活动到调试器要查看的范围的末尾 - 只有在发布版本中,您才会看到此行为. (4认同)
  • 而且为了完整性,这就是为什么在方法的_end_处设置`unusedLocalVar = null`通常是一种去优化. (4认同)