public static int Main(String[] args) { Display("To fully understand this sample, you should step through the"); Display("code in the debugger while monitoring the output generated.\n"); Display("NOTE: The demos in this application assume that no garbage"); Display(" collections occur naturally. To ensure this, the sample"); Display(" objects are small in size and few are allocated.\n"); Display("Main thread's hash code: " + Thread.CurrentThread.GetHashCode()); Introduction(); // GC introduction ResurrectionDemo(); // Demos object resurrection DisposeDemo(); // Demos the use of Dispose & Finalize FinalizationQDemo(); // Demos the use of SuppressFinalize & ReRegisterForFinalize GenerationDemo(); // Demos GC generations WeakRefDemo(false); // Demos WeakReferences without resurrection tracking WeakRefDemo(true); // Demos WeakReferences with resurrection tracking // Demos Finalize on Shutdown symantics (this demo is inline) Display(0, "\n\nDemo start: Finalize on shutdown.", +1); // When Main returns, obj will have its Finalize method called. BaseObj obj = new BaseObj("Shutdown"); // This is the last line of code executed before the application terminates. Display(-1, "Demo stop: Finalize on shutdown (application is now terminating)", 0); return(0); }
// This method demonstrates the unbalanced nature of ReRegisterForFinalize // and SuppressFinalize. The main point is if your code makes multiple // calls to ReRegisterForFinalize (without intervening calls to // SuppressFinalize) the Finalize method may get called multiple times. private static void FinalizationQDemo() { Display(0, "\n\nDemo start: Suppressing and ReRegistering for Finalize.", +1); // Since this object has a Finalize method, a reference to the object // will be added to the finalization queue. BaseObj obj = new BaseObj("Finalization Queue"); // Add another 2 references onto the finalization queue // NOTE: Don't do this in a normal app. This is only for demo purposes. GC.ReRegisterForFinalize(obj); GC.ReRegisterForFinalize(obj); // There are now 3 references to this object on the finalization queue. // Set a bit flag on this object indicating that it should NOT be finalized. GC.SuppressFinalize(obj); // There are now 3 references to this object on the finalization queue. // If the object were unreachable, the 1st call to this object's Finalize // method will be discarded but the 2nd & 3rd calls to Finalize will execute. // Sets the same bit effectively doing nothing! GC.SuppressFinalize(obj); obj = null; // Remove the strong reference to the object. // Force a GC so that the object gets finalized Collect(); // NOTE: Finalize is called twice because only the 1st call is suppressed! WaitForFinalizers(); Display(-1, "Demo stop: Suppressing and ReRegistering for Finalize.", 0); }
// This method demonstrates how weak references (WR) work. A WR allows // the GC to collect objects when GC determines it is time for a collection, for instance, when // system is under memory pressure (but this is not the only case when GC decides to start a collection). // WRs are useful to apps that have large amounts of easily-reconstructed // data that they want to keep around to improve performance. But, if the // system is low on memory, the objects can be destroyed and replaced when // the app knows that it needs it again. private static void WeakRefDemo(Boolean trackResurrection) { Display(0, String.Format("\n\nDemo start: WeakReferences that {0}track resurrections.", trackResurrection ? "" : "do not "), +1); // Create an object BaseObj obj = new BaseObj("WeakRef"); // Create a WeakReference object that refers to the new object WeakReference wr = new WeakReference(obj, trackResurrection); // The object is still reachable, so it is not finalized. Collect(); WaitForFinalizers(); // The Finalize method should NOT execute obj.Display("Still exists"); // Let's remove the strong reference to the object obj = null; // Destroy strong reference to this object // The following line creates a strong reference to the object obj = (BaseObj)wr.Target; Display("Strong reference to object obtained: " + (obj != null)); obj = null; // Destroy strong reference to this object again. // The GC considers the object to be unreachable and collects it. Collect(); WaitForFinalizers(); // Finalize should run. // This object resurrects itself when its Finalize method is called. // If wr is NOT tracking resurrection, wr thinks the object is dead // If wr is tracking resurrection, wr thinks the object is still alive // NOTE: If the object referred to by wr doesn't have a Finalize method, // then wr would think that the object is dead regardless of whether // wr is tracking resurrection or not. For example: // Object obj = new Object(); // Object doesn't have a Finalize method // WeakReference wr = new WeakReference(obj, true); // obj = null; // Collect(); // WaitForFinalizers(); // Does nothing // obj = (Object) wr.Target; // returns null // The following line attempts to create a strong reference to the object obj = (BaseObj)wr.Target; Display("Strong reference to object obtained: " + (obj != null)); if (obj != null) { // The strong reference was obtained so this wr must be // tracking resurrection. At this point we have a strong // reference to an object that has been finalized but its memory // has not yet been reclaimed by the collector. obj.Display("See, I'm still alive"); obj = null; // Destroy the strong reference to the object // Collect reclaims the object's memory since this object // has no Finalize method registered for it anymore. Collect(); WaitForFinalizers(); // We should see nothing here obj = (BaseObj)wr.Target; // This now returns null Display("Strong reference to object obtained: " + (obj != null)); } // Cleanup everything about this demo so there is no affect on the next demo obj = null; // Destroy strong reference (if it exists) wr = null; // Destroy the WeakReference object (optional) Collect(); WaitForFinalizers(); // NOTE: You are dicouraged from using the WeakReference.IsAlive property // because the object may be killed immediately after IsAlive returns // making the return value incorrect. If the Target property returns // a non-null value, then the object is alive and will stay alive // since you have a reference to it. If Target returns null, then the // object is dead. Display(-1, String.Format("Demo stop: WeakReferences that {0}track resurrections.", trackResurrection ? "" : "do not "), 0); }