← Back to Articles         
Memory Management and Garbage Collection - Part 1

Memory Management and Garbage Collection - Part 1

Published on 12 Oct 2026     7 min read C#
Memory Management & Garbage Collection

C# Memory Management and Garbage Collection

1. What is Garbage Collection in .NET?

Garbage Collection (GC) is an automatic memory management process in .NET that releases memory occupied by managed objects that are no longer reachable by the application.

Example:

class Employee
{
    public string Name { get; set; }
}

void CreateEmployee()
{
    Employee emp = new Employee();
    emp.Name = "John";
}

Explanation:

  • An Employee object is created on the managed heap.

  • The emp variable references that object.

  • After the method finishes, the local reference disappears.

  • If no other references exist, the object becomes eligible for garbage collection.

  • The GC reclaims its memory during a future collection.

Key Points:

  • GC is managed by the .NET CLR.

  • Automatically reclaims memory of unreachable managed objects.

  • Developers generally do not need to manually free managed memory.

  • GC.Collect() can request garbage collection but should normally be avoided.

  • GC does not guarantee immediate memory release.

 

2. How Does the Garbage Collector Work?

The Garbage Collector identifies objects that are still reachable and reclaims memory occupied by unreachable objects.

GC Process:

Application creates objects
          |
          v
Objects allocated on managed heap
          |
          v
GC determines collection is needed
          |
          v
Identify reachable objects
          |
          v
Mark reachable objects as live
          |
          v
Reclaim memory of unreachable objects
          |
          v
Compact memory (when applicable)
          |
          v
Application continues

Example:

class Customer
{
    public string Name { get; set; }
}

Customer c1 = new Customer();
Customer c2 = new Customer();

c1 = null;

Explanation:

  • Two objects are created.

  • c1 = null removes one reference.

  • If no other references exist, the first object becomes eligible for GC.

  • The second object remains reachable through c2.

Key Points:

  • GC uses reachability analysis to identify live objects.

  • GC roots include local references, static references, and other runtime roots.

  • GC typically uses marking and compaction for the small object heap.

  • Garbage collection can temporarily pause managed execution.

  • Setting a variable to null does not immediately trigger GC.

 

3. What Are Generation 0, Generation 1, and Generation 2?

.NET uses generational garbage collection to improve performance.

Objects are grouped into three generations based on how many collections they have survived.

Generation

Description

Collection frequency

Gen 0

Newly created objects

Most frequent

Gen 1

Objects surviving Gen 0 collections

Less frequent

Gen 2

Long-lived objects

Least frequent

Example:

class Employee
{
    public string Name { get; set; }
}

Employee emp = new Employee();

Console.WriteLine(GC.GetGeneration(emp));

Typical Output:

0

Explanation:

  • A newly created small object normally starts in Generation 0.

  • If it survives a Gen 0 collection, it may move to Generation 1.

  • If it survives further collections, it may eventually move to Generation 2.

Diagram:

New Object
    |
    v
Generation 0
    |
    | Survives collection
    v
Generation 1
    |
    | Survives collection
    v
Generation 2

Key Points:

  • Gen 0 contains short-lived objects.

  • Gen 1 acts as a buffer between short-lived and long-lived objects.

  • Gen 2 contains long-lived objects.

  • A Gen 2 collection also includes Gen 0 and Gen 1.

  • Large objects (normally 85,000 bytes or more) use the Large Object Heap, which is collected with Gen 2.

 

4. What Is the Difference Between Stack and Heap Memory?

The stack is primarily used for method execution and local storage, while the heap stores dynamically allocated objects.

Stack

Heap

Stores stack frames and certain local values

Stores class instances and arrays

Managed through method execution

Managed through GC for managed objects

Very fast allocation

Allocation is generally fast but involves GC management

Typically thread-specific

Objects can be shared between threads

Limited stack space

Generally much larger memory area

Example:

class Employee
{
    public int Id;
}

void Test()
{
    int age = 30;

    Employee emp = new Employee();
    emp.Id = 101;
}

Conceptual Memory Diagram:

STACK                         HEAP
-------------------           -------------------
age = 30
emp (reference) ------------> Employee Object
                              Id = 101
-------------------           -------------------

Explanation:

  • age is a local value-type variable, typically stored in the stack frame.

  • emp is a local reference variable, typically stored in the stack frame.

  • The Employee object is allocated on the managed heap.

  • The object's Id field is stored as part of that object.

Key Points:

  • Value types are not always stored on the stack.

  • Value-type fields inside class objects are stored within those heap objects.

  • Reference-type objects are normally allocated on the managed heap.

  • The stack is automatically unwound as methods return.

  • Heap memory is reclaimed by GC when objects become unreachable.

 

5. What Is the Difference Between Managed and Unmanaged Resources?

Managed resources are objects whose memory is managed by the .NET Garbage Collector.

Unmanaged resources are operating system or native resources that require explicit cleanup, either directly or through a managed wrapper.

Managed Resources

Unmanaged Resources

Memory managed by GC

Not automatically released by GC

Examples: C# objects, arrays

Examples: native handles, native memory

Memory reclaimed automatically

Require explicit release

Usually no manual memory cleanup

Often handled through IDisposable

Example:

// Managed object
List<int> numbers = new List<int>();

// Managed wrapper around a file resource
using FileStream fs = new FileStream(
    "test.txt",
    FileMode.OpenOrCreate
);

Explanation:

  • List<int> is a managed object.

  • FileStream is also a managed object, but it wraps an operating system file handle.

  • The using declaration ensures Dispose() is called when the variable goes out of scope.

  • This releases the file resource promptly rather than waiting for garbage collection.

Key Points:

  • GC manages object memory, not the lifetime of all external resources.

  • File handles, socket handles, and native memory require proper cleanup.

  • IDisposable provides a standard cleanup mechanism.

  • Prefer using or await using for disposable resources.

  • A database connection object is managed, but it controls external resources that must be released promptly.

 

6. What Is the Difference Between Dispose() and a Finalizer?

Both are related to resource cleanup, but their execution and purpose are different.

Dispose() provides deterministic cleanup, whereas a finalizer provides a fallback cleanup mechanism for certain unmanaged resources.

Dispose()

Finalizer

Called explicitly or through using

Invoked by the GC finalization mechanism

Deterministic cleanup

Non-deterministic cleanup

Implements IDisposable

Uses ~ClassName() syntax

Can release managed and unmanaged resources appropriately

Primarily for direct unmanaged-resource cleanup

Preferred approach

Fallback mechanism

Example:

class ResourceManager : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Dispose called");

        GC.SuppressFinalize(this);
    }

    ~ResourceManager()
    {
        Console.WriteLine("Finalizer called");
    }
}

using (ResourceManager resource = new ResourceManager())
{
    Console.WriteLine("Using resource");
}

Output:

Using resource
Dispose called

Explanation:

  • The object is created inside a using block.

  • At the end of the block, Dispose() is called automatically.

  • GC.SuppressFinalize(this) prevents finalization for this instance.

  • The finalizer is not executed in this example.

  • The example demonstrates lifecycle behavior; a real implementation must actually release its owned resources.

Key Points:

  • Dispose() is used for immediate, predictable resource cleanup.

  • A finalizer runs at an unspecified time and may never run before process termination.

  • Finalizers should generally be implemented only when directly owning unmanaged resources.

  • Prefer SafeHandle rather than writing a custom finalizer.

  • GC.SuppressFinalize(this) avoids unnecessary finalization after successful disposal.

  • Dispose() does not directly free the managed object's heap memory; GC handles that later.

 

Interview Quick Revision

Question

Important answer

What is GC?

Automatic managed memory reclamation

How does GC work?

Finds reachable objects and reclaims unreachable objects

What are generations?

Gen 0, Gen 1, and Gen 2 optimize collection

Stack vs Heap?

Stack supports method execution; heap stores allocated objects

Managed vs Unmanaged?

GC-managed memory vs resources needing explicit cleanup

Dispose vs Finalizer?

Deterministic cleanup vs non-deterministic fallback

Important interview point: Garbage Collection and Dispose() solve different problems. GC reclaims managed memory, while Dispose() releases resources promptly.

← Back to Articles