Garbage Collection C#
Garbage collection is a background process which runs deterministically and cleans unreferenced managed objects from the memory.
Some definitions which are important to know are as follows:-
Heap:- Portion of memory where dynamically allocated objects resides.
Managed Heap:- Whenever we start any process or run our .NET code, it
reserves some space in the memory which is contiguous and
it’s called managed heap.
Those were the days when the developers would be required to release the memory which they have allocated for the objects.
It’s the developers responsibility to manage the memory, and this brings some issues during development.
- If we create a new object but forget to delete it, it will persist in the memory for a long time even if we didn’t want to use it.
- If our variable is referencing an object in the memory, and later that variable started referencing another object in the memory, then the previous object will persist in memory even if no variable is referencing this object. It’s called memory leak. Object is not referenced by any variable and also not required but still in memory.
To overcome these scenarios, .NET came up with the garbage collector, which will take care of deleting the objects from the memory.
But, the garbage collector is limited to allocate or release the memory of managed code only, it does not allocate or release the unmanaged memory.
Managed code written in the .NET might access unmanaged code.
- for ex:- Connecting with database using SQL, Oracle classes, Network calls made from managed code, accessing files.
Even though we are writing the managed code, but this code is using the unmanaged code. So, as a developer it’s our responsibility to release the memory once the work of these objects are completed.
How do we release the memory then?
NET provides the IDisposable interface for the types (example:- class) which are using the unmanaged code, for ex, network calls, database connection etc.
Those types needs to implement IDisposable interface and provides the implementation of the Dispose() method and write their own logic to release the memory.
And our task as a developer is that once we are done with these objects, we should call the dispose method on these objects.
.NET also provides a Finalize method, in case developer forgets to call the dispose method on this object.
GC releases the memory even if we forget to call the dispose method, if that class also implements the finalize, but the crux here is that finalize in indeterministic and dispose is deterministic.
It means we have control over the dispose method, when to call. But that finalize will be in hand of GC, when it calls.
var fileProcessor = new FileProcessor();
fileProcessor.Dispose();
class FileProcessor : IDisposable
{
bool disposed = false;
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
public void Dispose()
{
Dispose(true);
//supress finalization
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (this.disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
}
//free unmanaged objects here
//
this.disposed = true;
}
}