C# 從基礎到精通 — 第 9 講
了解 GC 的效能、值類型和分配成本
該部落格上撰寫的文章是出於教學目的而創建的。 另外,文章中的資訊可能不正確,請謹慎。
在 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的產生和收集方法由運行時管理,短命對像不一定是問題。 以犧牲可讀性為代價預先優化所有程式碼只能增加維護成本。
您應該使用分析器來確定配額和停頓是否為真正的瓶頸,然後套用池化、緩衝區重複使用和值鍵入。 效能最佳化不是猜測語法的任務,而是減少測量成本原因的任務。