Writing code for the .NET Framework provides the benefit of automatic memory management. This means that you allocate the memory you need with the new operator, but you don't have to worry about freeing the memory. An internal garbage collector within the CLR determines when memory is no longer referenced and cleans it up when necessary.
The garbage-collection feature keeps the memory clean while the application is executing, which frees you from writing the code to manage the memory allocations and deleting allocated memory when it is no longer needed.
Typically in unmanaged code, it is bad practice to allocate small amounts of memory or classes repeatedly and then delete them. The memory becomes fragmented, and the overhead for the application is too high and brings down the performance of the application. To combat this problem, developers had to use objects conservatively by reusing them when possible, especially when they might be allocated and deleted multiple times during the operation of the application.
The managed memory within the .NET Framework doesn't have those issues with short-term objects. Objects that are created and go out of scope frequently are optimized by the memory manager and reused when possible. Furthermore, even with repeated allocating and freeing of memory, the runtime has the ability to defragment and optimize free memory within the runtime environment. Therefore, it is entirely acceptable to use short-term memory objects in the .NET Framework to simplify your code, and the application won't suffer with a performance hit.
With all the great features, there is a downside that causes object-oriented C++ developers some issues. With the new memory manager, you have no idea when an object may be destructed because it happens with the garbage collector. Therefore, you can't clean up a class or perform automatic features within the destructor of the class. The class destructor is not directly callable, and there is no delete operator to call the destructor for you as there is in unmanaged C++ code.
The solution is to provide a Dispose() method within the class definition. However, the Dispose() method is not called automatically, which means you have to add code to call Dispose() for each class that needs to be cleaned up when it isn't being used. When the garbage collector is ready to remove a class from memory, it does call the Finalize() method if one is defined within the object. Then, the object is finally deleted from memory.
In general, you should leave the garbage collector alone and let it decide when it's appropriate to reclaim memory. However, sometimes it is a good idea in an application to force the garbage collector to remove unused classes from memory. This is often the case when your application has just finished a memory-intensive process that created several objects that are no longer needed now that the process is complete.
Forcing the garbage collector to clean up the memory can increase your application's performance in such instances. By placing a call to the GC.Collect() method, your application indicates to the garbage collector that it needs to clean up the memory now rather than later. Calling this method too often, however, can cause performance issues within your application. Therefore, be careful when calling it, and only do so when you need to clean up a lot of memory that is no longer needed.