In Swift werden Werttypen (value types), wie struct, enum und tuple, normalerweise im Stack platziert, während Referenztypen (reference types), wie class, im Heap liegen.
Stack-Allocation ist schnell, automatisch und wird zur Speicherung von lokalen Variablen mit kurzer Lebensdauer verwendet. Heap-Allocation erfordert zusätzliche Kosten und wird für Objekte mit unbestimmter Lebensdauer oder Größe verwendet.
Beispiel:
struct Point { var x: Int; var y: Int } let p1 = Point(x: 2, y: 3) // Im Stack class Node { var value: Int; init(value: Int) { self.value = value } } let n1 = Node(value: 5) // Im Heap
Nuancen:
Leistung: Stack-Allocation ist schneller, da sie keine Arbeit mit dem Speicher im Heap und kein Management der Lebensdauer von Objekten erfordert.
Werden alle Strukturen (struct) immer ausschließlich im Stack platziert?
Antwort: Nein! Obwohl Strukturen Werttypen sind und häufig im Stack platziert werden, kann der Compiler sie im Heap speichern, wenn sie innerhalb eines Klasse-Objekts, Arrays, Dictionaries oder als captured value in Closures verwendet werden. Zum Beispiel:
class Box { var point: Point init(point: Point) { self.point = point } } let box = Box(point: Point(x: 1, y: 2))
Hier wird die Instanz Point im Heap gespeichert, da sie zur Klasse Box gehört.
Geschichte
Ein Entwickler versuchte, die Leistung von Strukturen zu optimieren, in dem Glauben, dass große Strukturen immer im Stack liegen würden, und berücksichtigte nicht, dass Sammlungen (Array, Dictionary) Heap-Allocation verwenden, was zu einem unerwarteten Anstieg des Speicherverbrauchs im Projekt führte.
Geschichte
Im Projekt wurde nicht berücksichtigt, dass Closures einen Wert der Struktur erfassen, der im Heap landet, was die Lebensdauer des Objekts beeinflusst. Dies erhöhte die Lebensdauer der Variablen und führte zu Speicherlecks, da man mit einer automatischen Freigabe beim Verlassen des Gültigkeitsbereichs rechnete.
Geschichte
Die Verwendung von Arrays schwerer Strukturen ohne Verständnis von Copy-on-Write führte zu unerwartet teuren Kopieroperationen durch die Übergabe von Sammlungen zwischen Threads, was die Leistung beeinträchtigte und Verzögerungen in der Benutzeroberfläche verursachte.