Can a conforming C# compiler optimize away a local

2019-04-20 01:40发布

问题:

See also these related resources:

  • Does the .NET garbage collector perform predictive analysis of code? (on Stack Overflow)
  • WP7: When does GC Consider a Local Variable as Garbage (blog article on MSDN)

In other words:

Can an object referenced by a local variable be reclaimed before the variable goes out of scope (eg. because the variable is assigned, but then not used again), or is that object guaranteed to be ineligible for garbage collection until the variable goes out of scope?

Let me explain:


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) ...
}

In this code example, I obviously have to plan for the possibility that the new'ed object is reclaimed by the garbage collector; therefore the if statement.

(Note that I'm using weakRef for the sole purpose of checking if the new'ed object is still around.)


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);
}

The main change in this code example from the previous one is that the new'ed object is strongly referenced by a local variable (unusedLocalVar). However, this variable is never used again after the weak reference (weakRef) has been created.


Question: Is a conforming C# compiler allowed to optimize the first two lines of Case_2 into those of Case_1 if it sees that unusedLocalVar is only used in one place, namely as an argument to the WeakReference constructor? i.e. is there any possibility that the assertion in Case_2 could ever fail?

回答1:

It doesn't matter what the C# compiler does - the JITter/GC are allowed to clean up local references once they're no longer alive in a method body. Look at the docs for GC.KeepAlive

Also, this powerpoint presentation, especially from slide 30 onwards, helps to explain what the JIT/GC can get up to.



回答2:

While my question has been answered, I thought I'd post this relevant piece of information I just found on the MSDN blog article "WP7: When does GC Consider a Local Variable as Garbage" by abhinaba:

[T]he ECMA specification (ECMA 334 Section 10.9) […] states

“For instance, if a local variable that is in scope is the only existing reference to an object, but that local variable is never referred to in any possible continuation of execution from the current execution point in the procedure, an implementation might (but is not required to) treat the object as no longer in use.”

This says it all. The mentioned article also says that the .NET framework (at least in Release mode) will perform predictive analysis and free such objects, while the .NET Compact Framework won't (for performance reasons).



回答3:

Is a conforming C# compiler allowed to optimize the first two lines of Case_2 into those of Case_1 if it sees that unusedLocalVar is only used in one place, namely as an argument to the WeakReference constructor?

The two definitions are equivalent so transforming from one to the other is not an "optimization" because neither is more efficient.

i.e. is there any possibility that the assertion in Case_2 could ever fail?

Yes. A production compiler is not likely to retain a reference unnecessarily so it will be removed, the GC will not see it as a global root and will collect that object.

Note that garbage collectors do not see your program in terms of variables and scope. Those high-level concepts have long since been compiled away by the time your code gets to the garbage collector. The GC sees only registers, thread stacks and global variables.