Isn’t .NET Garbage collector coolest of all? Apart from providing the runtime’s virtual memory, it provides our applications the boundless virtual memory by recovering memory that is never again being used and making it accessible to our code again. Thus, it additionally takes away the saddle of allocating and free memory indisputably. But at instances it still matters to know how, when and where the memory is allocated. The reason is very simple and straight, if we write efficient codes, it would make our Garbage collector spend less CPU time assigning and liberating the memory and hence that would make our applications less time and space consuming.
The Garbage collector and generations:
When we run a .NET application, the runtime allocates a big part of the memory where it manages the allocation and removal of objects. Allocations are done whenever we create a new object instance and deallocations are managed by the Garbage Collector (GC).
The increase the efficiency, the garbage collector was designed to be generational- all the new objects created are allocated in the first generation (Gen0). When a GC is running, it normally attempts to clean up objects from this Gen0 by looking at the references pointing to our objects. If it’s “No longer in use”, its frees up its memory; “Still in use” , the objects are moved to Gen1. A similar pattern is followed on Gen1 where the objects in use are moved to Gen2 and the process goes so on.
The GC runs most often on Gen0 because new objects usually have few other objects pointing to them and hence it makes the clean-up process faster. For instance lets take an example of the objects used in the scope of a method or may be a web request that allocated some objects that are obsolete once the response is delivered. The more time the object spends in the memory, more it becomes difficult to clean up. So the GC runs less on Gen1 and even less on Gen2. Objects in higher generations live longer, so they are not checked every time the GC runs as it consumes CPU and freezes the application. Sometimes on very big server applications, GC cycles can even block incoming requests.
One way of avoiding objects from moving into further generations is by using “IDisposable”(To free the resources) and making sure that Dispose() method is called whenever the object is no longer need(for example by using ausing statement). This will ensure the GC that there is no reason to believe that our objects’ references object cannot be reclaimed. But one as to careful with the finalizers in .Net, when GC runs along and finds an object that is ready to be collected; it is moved to the finalizer queue. Also one should keep in mind that finalizers are not guaranteed to run, its better to have no finalizer then a wrong one.
To sum up, one can conclude that, it is better to optimize our allocations and make sure that they can be collected quickly, if possible while they are on Gen0 or not allocating at all.