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
andSpan<T>
to reduce heap usage and boost performance.
This content originally appeared on DEV Community and was authored by hamza zeryouh