| Start |
|---|
| A basic example of (garbage) collection Given the following class: A program that creates an instance, even without using it: Produces the following output: If nothing else happens, the object is not finalized until the program ends (which frees all objects on the managed heap, finalizing these in the process). It is possible to force the Garbage Collector to run at a given point, as follows: Which produces the following result: This time, as soon as the Garbage Collector was invoked, the unused (aka "dead") object was finalized and freed from the managed heap. |
| Live objects and dead objects - the basics Rule of thumb: when garbage collection occurs, "live objects" are those still in use, while "dead objects" are those no longer used (any variable or field referencing them, if any, has gone out of scope before the collection occurs). In the following example (for convenience, FinalizableObject1 and FinalizableObject2 are subclasses of FinalizableObject from the example above and thus inherit the initialization / finalization message behavior): The output will be: At the time when the Garbage Collector is invoked, FinalizableObject1 is a dead object and gets finalized, while FinalizableObject2 is a live object and it is kept on the managed heap. |
| Multiple dead objects What if two (or several) otherwise dead objects reference one another? This is shown in the example below, supposing that OtherObject is a public property of FinalizableObject: This produces the following output: The two objects are finalized and freed from the managed heap despite referencing each other (because no other reference exists to any of them from an actually live object). |
| Weak References Weak references are... references, to other objects (aka "targets"), but "weak" as they do not prevent those objects from being garbage-collected. In other words, weak references do not count when the Garbage Collector evaluates objects as "live" or "dead". The following code: Produces the output: The object is freed from the managed heap despite being referenced by the WeakReference variable (still in scope when the Garbage collector was invoked). Consequence #1: at any time, it is unsafe to assume whether a WeakReference target is still allocated on the managed heap or not. Consequence #2: whenever a program needs to access the target of a Weakreference, code should be provided for both cases, of the target being still allocated or not. The method to access the target is TryGetTarget: The generic version of WeakReference is available since .Net 4.5. All framework versions provide a non-generic, untyped version that is built in the same way and checked as follows: |
| Dispose() vs. finalizers Implement Dispose() method (and declare the containing class as IDisposable) as a means to ensure any memory-heavy resources are freed as soon as the object is no longer used. The "catch" is that there is no strong guarantee the the Dispose() method would ever be invoked (unlike finalizers that always get invoked at the end of the life of the object). One scenario is a program calling Dispose() on objects it explicitly creates: Another scenario is declaring a class to be instantiated by the framework. In this case the new class usually inherits a base class, for instance in MVC one creates a controller class as a subclass of System.Web.Mvc.ControllerBase. When the base class implements IDisposable interface, this is a good hint that Dispose() would be invoked properly by the framework - but again there is no strong guarantee. Thus Dispose() is not a substitute for a finalizer; instead, the two should be used for different purposes:
|
| Proper disposal and finalization of objects As Dispose() and finalizers are aimed to different purposes, a class managing external memory-heavy resources should implement both of them. The consequence is writing the class so that it handles well two possible scenarios:
One solution is writing the cleanup code in such a way that running it once or twice would produce the same result as running it only once. Feasibility depends on the nature of the cleanup, for instance:
A safer solution is ensuring by design that the cleanup code is called once and only once whatever the external context. This can be achieved the "classic way" using a dedicated flag: Alternately, the Garbage Collector provides a specific method SuppressFinalize() that allows skipping the finalizer after Dispose has been invoked: RemarksThe Garbage Collector is aimed to lower the program cost in terms of allocated memory, but doing so has a cost in terms of processing time. In order to achieve a good overall compromise, there are a number of optimizations that should be taken into consideration while programming with the Garbage Collector in mind:
|
Read Article
https://develop.horje.com/learn/1434/reference