← SEARCHABLE ARCHIVE
C# · 2026-08-10

从 C# 基础到掌握 — 第 9 集

了解 GC 的性能、值类型和分配成本

INTERACTIVE READING MODE →

该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。

在 C# 中,GC 管理内存,但分配成本并没有消失。 特别是在恒定帧时间很重要的程序中(例如游戏),您需要知道对象何时创建。

值类型和引用类型

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

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

值类型包含变量中的值本身,并在赋值时被复制。 对于引用类型,将复制指向托管堆中对象的引用。

不要只记住值类型总是在堆栈上而引用类型总是很慢。 实际存储位置和成本将根据使用环境、大小和运行时优化而有所不同。

避免拳击

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

当值类型被视为对象或实现的接口时,可能会发生装箱。 使用泛型集合,您可以存储值类型,而无需将其更改为对象。

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

减少重复分配

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

void CollectVisible()
{
    visibleMonsters.Clear();

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

通过重用具有容量的缓冲区而不是每次创建新列表,可以减少分配数量。 字符串连接、捕获 lambda 和 LINQ 结果生成也会导致迭代路径中的分配。

先测量

GC的生成和收集方法由运行时管理,短命对象不一定是问题。 以牺牲可读性为代价预先优化所有代码只能增加维护成本。

您应该使用分析器来确定配额和停顿是否是真正的瓶颈,然后应用池化、缓冲区重用和值键入。 性能优化不是猜测语法的任务,而是减少测量成本原因的任务。