🧠Stack vs Heap in C# (.NET Core) – Complete Guide with Examples



This content originally appeared on DEV Community and was authored by hamza zeryouh

Memory in C# (and .NET Core) is divided into two key regions: Stack and Heap. Both are essential for memory management, but they serve different purposes and behave differently. Understanding how they work helps you write faster and more reliable applications.

🔷 The Stack in C

The Stack is a memory region used to store:

  • Value types (int, bool, struct, etc.)
  • Local variables
  • Method call data (like parameters and return addresses)

It’s called a “stack” because it works like a stack of plates – the last item pushed is the first one popped. Once a method ends, all its stack-allocated memory is cleaned up automatically.

✅ Key Characteristics

  • Automatic cleanup after method execution
  • Fast access due to LIFO structure
  • Limited size (typically 1MB per thread)
  • Stores value types and method data
  • No memory leaks or manual management

💡 Stack Memory Example

void UseStack()
{
    int a = 10;       // Stored on the stack
    int b = 20;       // Also on the stack
    int result = a + b;
    Console.WriteLine(result); // Output: 30
}

Here, all variables (a, b, result) are value types, so they are allocated on the stack. When the method finishes, this memory is automatically freed.

🔶 The Heap in C

The Heap is a region of memory used for dynamic memory allocation. It’s where reference types (objects, arrays, classes) live. Heap memory is managed by the Garbage Collector (GC) in .NET Core, which frees unused objects automatically.

✅ Key Characteristics

  • Used for reference types (classes, arrays, etc.)
  • Garbage collected, not cleaned up immediately
  • Slower access due to pointer dereferencing
  • Flexible size, can grow at runtime
  • Allows objects to live beyond method scope

💡 Heap Memory Example

class Person
{
    public string Name;
}

void UseHeap()
{
    Person p = new Person();  // Allocated on the heap
    p.Name = "Alice";
    Console.WriteLine(p.Name);  // Output: Alice
}

In this case:

  • p is a reference stored on the stack.
  • The actual Person object is stored on the heap.

The GC eventually frees the heap memory once there are no more references to the object.

🔄 Comparison Table: Stack vs Heap in C

Feature Stack Heap
Memory Management Automatic on method exit Automatic via Garbage Collector
Type Stored Value types (int, struct) Reference types (class, array)
Access Speed Very fast Slower due to indirection
Lifetime Scoped to function/method Lives as long as references exist
Size Limit Fixed (usually ~1MB/thread) Dynamically growing
Leak Risk None Possible if references persist
Use Case Temporary/local values Long-lived or shared objects

🔁 Rewriting Heap to Use Stack (Optimization Tip)

You can optimize memory by replacing heap allocation with stack allocation using struct or Span<T>.

🆚 class (Heap) vs struct (Stack)

// Heap
class PointClass
{
    public int X;
    public int Y;
}

// Stack
struct PointStruct
{
    public int X;
    public int Y;
}

void Compare()
{
    PointClass pc = new PointClass();   // Heap
    PointStruct ps = new PointStruct(); // Stack
}
  • PointClass is a reference type, stored on the heap.
  • PointStruct is a value type, stored on the stack.

Use struct when:

  • You need fast, short-lived data.
  • You don’t need inheritance or polymorphism.

⚡ Advanced Stack Usage: Span<T> and stackalloc

void UseSpan()
{
    Span<int> numbers = stackalloc int[5];  // Stack-based array
    numbers[0] = 10;
    numbers[1] = 20;
    Console.WriteLine(numbers[0] + numbers[1]);  // Output: 30
}
  • stackalloc allocates memory directly on the stack.
  • Span<T> provides safe and efficient access to that memory.
  • Useful in performance-critical scenarios (e.g., parsing, buffer processing).

⚠ Note: You cannot return Span<T> from a method-it must stay within the method scope because it’s backed by stack memory.

🚨 Common Memory Problems

❗ Stack Overflow

Occurs when you use too much stack memory, usually due to infinite or very deep recursion.

void Recurse()
{
    Recurse();  // Stack overflow
}

Each call pushes a new stack frame. Eventually, the stack runs out of space and crashes.

❗ Memory Leaks (Heap)

While C# has a garbage collector, memory leaks can still happen if you hold on to references unintentionally (e.g., through static variables or events).

class BigObject
{
    public byte[] Data = new byte[1024 * 1024]; // 1MB
}

static List<BigObject> leakyList = new();

void LeakMemory()
{
    leakyList.Add(new BigObject());  // Keeps growing, never released
}

✅ Best Practices

  • Use the Stack when:

    • You know the data size at compile time
    • Data only lives within a method
    • Performance is critical
  • Use the Heap when:

    • You need reference semantics
    • Objects are large or dynamic in size
    • You need data to persist across method calls
  • Avoid memory leaks:

    • Unsubscribe from events
    • Dispose of IDisposable objects
    • Don’t retain unnecessary references

🔚 Final Thoughts

In .NET Core, memory management is largely automated. However, understanding the difference between Stack and Heap gives you control to optimize performance and avoid hidden bugs.

TL;DR:

  • Stack = Fast, small, temporary, automatic cleanup.
  • Heap = Flexible, long-lived, garbage collected.
  • Use struct and Span<T> to reduce heap usage and boost performance.


This content originally appeared on DEV Community and was authored by hamza zeryouh