programowanieiOS programista

Jak działa przydzielanie na stosie i w stercie w Swift? W jakich przypadkach obiekty są umieszczane na stosie lub w stercie, jak wpływa to na wydajność i cykl życia obiektów?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Swift typy wartości (typu value), takie jak struct, enum i tuple, zwykle są umieszczane na stosie, podczas gdy typy referencyjne (typu reference), takie jak class, są umieszczane w stercie (heap).

Przydzielanie na stosie jest szybkie, automatyczne i służy do przechowywania zmiennych lokalnych o krótkim czasie życia. Przydzielanie w stercie wymaga dodatkowych kosztów i jest używane dla obiektów o nieokreślonym czasie życia lub rozmiarze.

Przykład:

struct Point { var x: Int; var y: Int } let p1 = Point(x: 2, y: 3) // Na stosie class Node { var value: Int; init(value: Int) { self.value = value } } let n1 = Node(value: 5) // W stercie

Szczegóły:

  • Kompilator/optymalizator Swift może umieścić nawet struct w stercie, jeśli jest on zagnieżdżony w class lub umieszczony w kolekcji.
  • Typy wartości są kopiowane podczas przekazywania, co zazwyczaj prowadzi do kopiowania na stosie, ale Swift wdraża copy-on-write dla kolekcji.
  • Przydzielanie w stercie wymaga kontroli nad czasem życia obiektów (ARC). Obiekty na stosie są automatycznie usuwane po wyjściu ze zasięgu.

Wydajność: Przydzielanie na stosie jest szybsze, ponieważ nie wymaga pracy z pamięcią w stercie i zarządzania czasem życia obiektów.

Pytanie w pułapce

Czy wszystkie struktury (struct) zawsze są umieszczane wyłącznie na stosie?

Odpowiedź:
Nie! Chociaż struktury są typami wartości i często są umieszczane na stosie, kompilator może przechowywać je w stercie, jeśli znajdują się wewnątrz obiektu klasy, tablicy, słownika lub są używane jako captured value w closure. Na przykład:

class Box { var point: Point init(point: Point) { self.point = point } } let box = Box(point: Point(x: 1, y: 2))

Tutaj instancja Point będzie przechowywana w stercie, ponieważ należy do klasy Box.

Przykłady rzeczywistych błędów z powodu nieznajomości szczegółów tematu


Historia

Programista próbował zoptymalizować wydajność struktur, sądząc, że duże struktury zawsze będą przechowywane na stosie, i nie brał pod uwagę, że kolekcje (Array, Dictionary) używają przydzielania w stercie, co doprowadziło do nieoczekiwanego wzrostu zużycia pamięci w projekcie.


Historia

W projekcie nie uwzględniono, że closure przechwytuje wartość struktury, która trafia do sterty, wpływając na czas życia obiektu. To zwiększyło czas życia zmiennych i doprowadziło do wycieków pamięci, ponieważ oczekiwano automatycznego zwolnienia po wyjściu ze zasięgu.


Historia

Użycie tablic ciężkich struktur bez zrozumienia copy-on-write doprowadziło do nieoczekiwanie drogich operacji kopiowania w wyniku przekazywania kolekcji między wątkami, obniżając wydajność i powodując opóźnienia w UI.