← SEARCHABLE ARCHIVE
C# · 2026-08-10

C# from Basics to Mastery — Part 9

Understanding performance with GC, value types, and allocation costs

INTERACTIVE READING MODE →

The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.

In C#, GC manages memory, but allocation costs do not disappear. Especially in programs where a constant frame time is important, such as a game, you need to know when an object is created.

Value types and reference types

public readonly struct Damage
{
    public int Value { get; }
    public Damage(int value) => Value = value;
}

Damage first = new(10);
Damage second = first;

The value type contains the value itself in the variable and is copied when making an assignment. For reference types, references pointing to objects in the managed heap are copied.

Don't just memorize that value types are always on the stack and reference types are always slow. Actual storage location and cost will vary depending on usage context, size, and runtime optimization.

avoid boxing

int score = 100;
object boxed = score;
int restored = (int)boxed;

Boxing can occur when a value type is treated as an object or an implemented interface. Using a generic collection, you can store the value type without changing it to object.

var scores = new List<int>();
scores.Add(100);

Reduce repeated allocations

private readonly List<Monster> visibleMonsters = new(128);

void CollectVisible()
{
    visibleMonsters.Clear();

    foreach (Monster monster in monsters)
    {
        if (monster.IsVisible)
        {
            visibleMonsters.Add(monster);
        }
    }
}

The number of allocations can be reduced by reusing a buffer with capacity instead of creating a new list each time. String concatenation, capturing lambdas, and LINQ result generation can also cause allocations in the iteration path.

Measure first

GC generation and collection methods are managed by the runtime, and short-lived objects are not necessarily a problem. Pre-optimizing all code at the expense of readability can only increase maintenance costs.

You should use a profiler to determine if quotas and stalls are the real bottlenecks, then apply pooling, buffer reuse, and value typing. Performance optimization is not a task of guessing the grammar, but a task of reducing the causes of measured costs.