X hits on this document





85 / 396


static void Main() { RefB = new B(); RefA = new A(); RefB.Ref = RefA; RefB = null; RefA = null;

// A and B now eligible for destruction GC.Collect(); GC.WaitForPendingFinalizers();

// B now eligible for collection, but A is not if (RefA != null) Console.WriteLine("RefA is not null"); } }

In the above program, if the garbage collector chooses to run the destructor of A before the destructor of B, then the output of this program might be:

Destruct instance of A Destruct instance of B A.F RefA is not null

Note that although the instance of A was not in use and A’s destructor was run, it is still possible for methods of A (in this case, F) to be called from another destructor. Also, note that running of a destructor may cause an object to become usable from the mainline program again. In this case, the running of B’s destructor caused an instance of A that was previously not in use to become accessible from the live reference Test.RefA. After the call to WaitForPendingFinalizers, the instance of B is eligible for collection, but the instance of A is not, because of the reference Test.RefA.

To avoid confusion and unexpected behavior, it is generally a good idea for destructors to only perform cleanup on data stored in their object's own fields, and not to perform any actions on referenced objects or static fields.

3.10 Execution order

Execution of a C# program proceeds such that the side effects of each executing thread are preserved at critical execution points. A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. The critical execution points at which the order of these side effects must be preserved are references to volatile fields (§‎10.4.3), lock statements (§‎8.12), and thread creation and termination. The execution environment is free to change the order of execution of a C# program, subject to the following constraints:

Data dependence is preserved within a thread of execution. That is, the value of each variable is computed as if all statements in the thread were executed in original program order.

Initialization ordering rules are preserved (§‎10.4.4 and §‎10.4.5).

The ordering of side effects is preserved with respect to volatile reads and writes (§‎10.4.3). Additionally, the execution environment need not evaluate part of an expression if it can deduce that that expression’s value is not used and that no needed side effects are produced (including any caused by calling a method or accessing a volatile field). When program execution is interrupted by an asynchronous event (such as an exception thrown by another thread), it is not guaranteed that the observable side effects are visible in the original program order.

72Copyright Microsoft Corporation 1999-2003. All Rights Reserved.

Document info
Document views1478
Page views1478
Page last viewedTue Jan 24 18:08:27 UTC 2017