In Lektion 3.12.1 hat die Spalte Allocated die Entscheidungen getragen: Die Interpolation weist nur den fertigen String zu, der StringBuilder das Vierfache. Diese Lektion zeigt das Werkzeug, mit dem .NET selbst Zuweisungen spart: Span<T>, ein Blick auf ein Stück Speicher, das schon da ist. Mit ihm lesen Sie Teile eines Strings, ohne Teilstrings anzulegen, und parsen Text, ohne für jedes Feld eine Kopie zu machen. Das ist schneller und schont die Speicherbereinigung, macht den Code aber auch länger und verlangt Regeln, die der Compiler streng durchsetzt. Deshalb endet die Lektion mit einer Abwägung: Am Ende ist der CSV-Import der Kontakte aus K1 auf ReadOnlySpan<char> umgestellt, gemessen, und Sie wissen, ob die Kladde ihn so behält.

Wo Daten liegen

Ein .NET-Programm hat zwei Orte für Daten:

  • Der Stapel (Stack) gehört einem Thread. Jede Methode legt beim Aufruf ihre lokalen Variablen dort ab und gibt den Platz beim Rücksprung frei. Das kostet fast nichts, und aufräumen muss niemand.
  • Der Heap gehört dem Prozess. Dort liegt alles, was new für einen Referenztyp anlegt: Objekte von Klassen, Arrays, Strings. Was niemand mehr erreicht, räumt die Speicherbereinigung weg (Lektion 3.12.3), und das kostet Zeit.

Werttypen (int, DateTime, TimeOnly, ein struct, ein record struct) liegen dort, wo die Variable liegt: als lokale Variable auf dem Stapel, als Feld einer Klasse mit dem Objekt auf dem Heap. Referenztypen (string, Arrays, class, record) liegen immer auf dem Heap; die Variable hält nur einen Verweis. Ein Werttyp, der in eine Variable vom Typ object oder ein Interface gesteckt wird, wird in ein Objekt auf dem Heap kopiert (Boxing); das ist eine Zuweisung, die man im Code nicht sieht.

Jede Zuweisung auf dem Heap ist für sich billig. Teuer wird die Menge: Viele kurzlebige Objekte heißen viele Speicherbereinigungen der Generation 0, und jede hält alle Threads kurz an. In einem Dienst, der tausend Anfragen je Sekunde beantwortet, zählt jede Zuweisung tausendmal.