C# von den Grundlagen bis zum Profi — Folge 9
Verstehen der Leistung mit GC, Werttypen und Allokationskosten
Die in diesem Blog verfassten Artikel wurden mit dem Ziel erstellt, zu unterrichten. Außerdem können die Informationen im Artikel falsch sein, also seien Sie bitte vorsichtig.
In C# verwaltet GC den Speicher, aber die Zuordnungskosten verschwinden nicht. Besonders bei Programmen, bei denen eine konstante Frametime wichtig ist, wie etwa bei einem Spiel, muss man wissen, wann ein Objekt erstellt wird.
Werttypen und Referenztypen
public readonly struct Damage
{
public int Value { get; }
public Damage(int value) => Value = value;
}
Damage first = new(10);
Damage second = first;
Der Werttyp enthält den Wert selbst in der Variablen und wird bei einer Zuweisung kopiert. Bei Referenztypen werden Referenzen kopiert, die auf Objekte im verwalteten Heap verweisen.
Denken Sie nicht nur daran, dass Werttypen immer auf dem Stapel liegen und Referenztypen immer langsam sind. Der tatsächliche Speicherort und die tatsächlichen Kosten variieren je nach Nutzungskontext, Größe und Laufzeitoptimierung.
Vermeiden Sie Boxen
int score = 100;
object boxed = score;
int restored = (int)boxed;
Boxing kann auftreten, wenn ein Werttyp als Objekt oder implementierte Schnittstelle behandelt wird. Mithilfe einer generischen Sammlung können Sie den Werttyp speichern, ohne ihn in ein Objekt zu ändern.
var scores = new List<int>();
scores.Add(100);
Reduzieren Sie wiederholte Zuweisungen
private readonly List<Monster> visibleMonsters = new(128);
void CollectVisible()
{
visibleMonsters.Clear();
foreach (Monster monster in monsters)
{
if (monster.IsVisible)
{
visibleMonsters.Add(monster);
}
}
}
Die Anzahl der Zuweisungen kann reduziert werden, indem ein Puffer mit Kapazität wiederverwendet wird, anstatt jedes Mal eine neue Liste zu erstellen. Die Verkettung von Zeichenfolgen, die Erfassung von Lambdas und die Generierung von LINQ-Ergebnissen können ebenfalls zu Zuweisungen im Iterationspfad führen.
Zuerst messen
Die GC-Generierungs- und Sammlungsmethoden werden von der Laufzeit verwaltet, und kurzlebige Objekte stellen nicht unbedingt ein Problem dar. Eine Voroptimierung des gesamten Codes auf Kosten der Lesbarkeit kann die Wartungskosten nur erhöhen.
Sie sollten einen Profiler verwenden, um festzustellen, ob Kontingente und Verzögerungen die tatsächlichen Engpässe sind, und dann Pooling, Pufferwiederverwendung und Werttypisierung anwenden. Bei der Leistungsoptimierung geht es nicht darum, die Grammatik zu erraten, sondern darum, die Ursachen der gemessenen Kosten zu reduzieren.