Skip to content

Welcome to a new series where we will dive deep into optimization techniques at the C# language and .NET runtime level. These are the foundational elements that determine the core performance of your application.


C# Core Optimization Series

Part 1: Stack vs. Heap and the Power of struct

Welcome to a new series on C# and .NET optimization. We'll start with the most fundamental concept: where your data is stored. Whether it's on the Stack or the Heap has a profound impact on performance.


The Two Main Memory Areas

  1. The Stack:

    • Analogy: A stack of plates. You can only add a new plate to the top or remove the top plate. It's very fast and simple.
    • Characteristics:
      • Allocating and freeing memory is extremely fast (it's just moving a pointer).
      • It stores Value Types: int, double, bool, DateTime, and most importantly, structs.
      • Memory is automatically cleaned up when a method finishes.
  2. The Heap:

    • Analogy: A large, messy warehouse. When you need space, the manager (the Garbage Collector) has to find a big enough empty spot.
    • Characteristics:
      • Allocating memory is slower.
      • It stores Reference Types: string, object, arrays ([]), and instances of classes.
      • Memory is managed by the Garbage Collector (GC). The GC must periodically run to find and clean up objects that are no longer in use, which costs CPU time.

struct vs. class: The Performance Battle

This fundamental difference leads to significant performance consequences.

  • class (Reference Type):

    csharp
    var myObject = new MyClass();
    • The data for myObject is created on the Heap.
    • The myObject variable on the Stack is just a small pointer to the memory location on the Heap.
    • Cost: Heap allocation + future pressure on the GC.
  • struct (Value Type):

    csharp
    var myValue = new MyStruct();
    • All the data for myValue is created directly on the Stack (if it's a local variable).
    • The myValue variable is the data.
    • Benefit: No Heap allocation, no garbage for the GC. Extremely fast.

When Should You Use a struct for Optimization?

Even though structs are fast, they aren't always the best choice because they are copied when passed between methods.

The Golden Rule: Use a struct when your object is:

  1. Small: Ideally under 16 bytes.
  2. Immutable: Its fields do not change after it's created.
  3. Represents a single value: For example, a Point (x, y coordinates), a Color (R, G, B, A), or a KeyValuePair.

Examples:

csharp
// GOOD: Use a struct for a 2D point.
// It's small and represents a single value.
public readonly struct Point
{
    public double X { get; }
    public double Y { get; }
    // ... constructor
}

// BAD: Use a struct for a complex object.
// It's large, and copying it would be expensive.
public struct Person
{
    public string FirstName; // string is a reference type
    public string LastName;
    public int Age;
    // ...
}

Conclusion:

In "hot paths" (code that runs very frequently), replacing small classes with structs can significantly reduce pressure on the Garbage Collector. This leads to lower CPU usage and eliminates the "pauses" caused by the GC, making your application run smoother and more consistently.