Friday, August 14, 2020

Memory Management in DotNet Framework



Introduction of garbage collection:

Dot net having automatic memory management through garbage collection (GC) . With this feature dot net will allocate the memory, track and release (cleaned up) the object from memory. So developers need not to be worry about the memory release or manually write the code to clean up the objects from memory.
But in all the cases memory is not handled by the GC, GC is only working for the managed code and unmanaged resource object has to be cleaned up manually mean we have to write the code for that.
However, when we create objects that encapsulate unmanaged resources, we must explicitly(directly) release the unmanaged resources when we are finished using them in your application. The most common type of unmanaged resource is an object that wraps an operating system resource, such as a file, window, or network connection. Although the garbage collector is able to track the lifetime of an object that encapsulates an unmanaged resource, it does not have specific knowledge about how to clean up the resource.
Dot net divide the source code in two different cases as below:

  • Managed code: Dot net code which is executed by framework
  • Unmanaged code: Code does not handled by framework.
Hope with the above definition we are very much clear about memory management when we have to release memory explicitly (directly) and when we have to leave the memory management on GC (implicit memory management).

We can do the memory management by two ways:

  • Implicit : through GC, only for the managed code
  • Explicit: manually writing the code to clean up the resources, it can be either managed or unmanaged code.

Understanding Memory management

When we are creating the instance of a class with new keyword then class object occupy a memory location and assign an address (reference) to the object. These objects are created on heap with a sequence order. Heap having a special pointer begin at position 0 on the heap and is incremented for the size of the allocated object. This establishes the beginning point for the next object to be allocated. The process continues until memory is full.


In the above picture four objects A, B, C and D have been allocated on the heap. After each allocation the next object pointer pointes to the top of the last object allocated.

When heap is full and another object try to occupy space in memory then two things can happen as below:

  • If all objects are live and in use, an out of memory exception thrown.
  • Our program must clean some of the memory space in memory.

Inside the Garbage collection

The purpose of GC is to clean up the unused objects on heap which is no longer is used by other objects. When an object goes out of scope or all the references to it are set to null that all objects are going to be clean up by GC.

1. Live graph:  
Live graph (active object graph) generated by GC after visiting in all the available objects in memory. All objects which all are not in the live graph that all objects are no longer use in applications and going to be cleaned up by GC. After GC fire objects will be cleaned up and available object compact with each other in the heap. Now pointer will be pointing at the next available heap memory location.

2. GC process::  
Garbage collection process is happening in three stages as below:
  • Beginning GC: In this stage GC traverse the entire object to find the status of the object and build the live graph (active object graph). EX: As in the below figure A is the root object, pointing the object B and D. Further object B having the reference of the object F.
  • During GC: Since object C and E are no longer reference by any of the objects, so C and E is going to be cleaned up by GC. In the live graph these both objects C and E will not be available.
  • After GC: The last stage shows how heap objects are compact and next object pointer is reset and ready for the next object to allocated. 
Have a look to the below image for GC process:

Garbage collection optimization

Generation : The heap is organized into generations so it can handle long-lived and short-lived objects. Garbage collection primarily occurs with the reclamation of short-lived objects that typically occupy only a small part of the heap. There are three generations of objects on the heap:

  1. Generation 0: This is the youngest generation and contains short-lived objects. An example of a short-lived object is a temporary variable. Garbage collection occurs most frequently in this generation. Newly allocated objects form a new generation of objects and are implicitly generation 0 collections, unless they are large objects, in which case they go on the large object heap in a generation 2 collection. Most objects are reclaimed for garbage collection in generation 0 and do not survive to the next generation.
  2. Generation 1: This generation contains short-lived objects and serves as a buffer between short-lived objects and long-lived objects.
  3. Generation 2: This generation contains long-lived objects. An example of a long-lived object is an object in a server application that contains static data that is live for the duration of the process.
Garbage collections occur on specific generations as conditions warrant. Collecting a generation means collecting objects in that generation and all its younger generations. A generation 2 garbage collection is also known as a full garbage collection, because it reclaims all objects in all generations (that is, all objects in the managed heap).

Survival and Promotions Objects that are not reclaimed in a garbage collection are known as survivors, and are promoted to the next generation. Objects that survive a generation 0 garbage collection are promoted to generation 1; objects that survive a generation 1 garbage collection are promoted to generation 2; and objects that survive a generation 2 garbage collection remain in generation 2.

When the garbage collector detects that the survival rate is high in a generation, it increases the threshold of allocations for that generation, so the next collection gets a substantial size of reclaimed memory. The CLR continually balances two priorities: not letting an application's working set get too big and not letting the garbage collection take too much time.
Ephemeral Generations and Segments Because objects in generations 0 and 1 are short-lived, these generations are known as the ephemeral generations.

Ephemeral Generations and Segments Because objects in generations 0 and 1 are short-lived, these generations are known as the ephemeral generations.
Ephemeral generations must be allocated in the memory segment that is known as the ephemeral segment. Each new segment acquired by the garbage collector becomes the new ephemeral segment and contains the objects that survived a generation 0 garbage collection. The old ephemeral segment becomes the new generation 2 segment.

The ephemeral segment can include generation 2 objects. Generation 2 objects can use multiple segments (as many as your process requires and memory allows for).

The amount of freed memory from an ephemeral garbage collection is limited to the size of the ephemeral segment. The amount of memory that is freed is proportional to the space that was occupied by the dead objects.

Finalize and Destructor

Finalize or destructors are more expensive to clean up objects because this works in two round to cleaned the object from memory.

  • Finalize method called for the object and object move to Finalization queue.
  • Now when GC invoke, the entire object which all were available in the Finalize queue move to the F-Reachable queue. 
  • Still objects are not garbage, again when the GC fire then it identify these objects and cleaned up from the memory.

Dispose:

In some cases, you might want to provide programmers using an object with the ability to explicitly release these external resources before the garbage collector frees the object. If an external resource is scarce or expensive, better performance can be achieved if the programmer explicitly releases resources when they are no longer being used. To provide explicit control, implement the Dispose method provided by the IDisposable Interface. The consumer of the object should call this method when it is done using the object. Dispose can be called even if other references to the object are alive. Apply dispose method in the class is the best way to manage the unmanaged resource memory management.

// Design pattern for a base class.
public class Base: IDisposable
{
   //Implement IDisposable.
   public void Dispose() 
   {
              // Free other state (managed objects).
           GC.SuppressFinalize(this); 
   }

}
Real world example: Suppose in the program need to create an object to read a text file then text file object will be unmanaged code and require manual cleanup by IDisposable pattern.

public class TextReaderClass: IDisposable
{
   private TextReader fileReader;
   
   public TextReaderClass()
   {
       this. fileReader = new TextReader();
   }

   public void Dispose()
   {
        fileReader.Dispose();
       GC.SuppressFinalize(this);
   }
}

References:

http://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx

No comments:

Post a Comment

Azure Function or Serverless Function

In this blog I covered what is Azure function? Why to use azure function? How to create azure function from azure portal and how to pass pa...