Swift'te değer türleri (value types), yani struct, enum ve tuple genellikle stack'te, referans türleri (reference types), yani class ise heap'te yer alır.
Stack allocation hızlı, otomatik ve kısa ömürlü yerel değişkenleri saklamak için kullanılır. Heap allocation ek maliyet gerektirir ve belirsiz yaşam süresi veya boyutu olan nesneler için kullanılır.
Örnek:
struct Point { var x: Int; var y: Int } let p1 = Point(x: 2, y: 3) // Stack'te class Node { var value: Int; init(value: Int) { self.value = value } } let n1 = Node(value: 5) // Heap'te
Nuanuslar:
Performans: Stack allocation daha hızlıdır çünkü heap'teki bellek yönetimi ile uğraşmaz ve nesnelerin yaşam döngüsü ile ilgili yönetim gerektirmez.
Tüm yapılar (struct) her zaman sadece stack'te mi yer alır?
Cevap:
Hayır! Yapılar değer türleri olmasına rağmen genellikle stack'te yer alırlar, derleyici bunları bir sınıf nesnesinin içinde, dizide, sözlükte veya closure içinde captured value olarak kullanıldıklarında heap'te saklayabilir. Örneğin:
class Box { var point: Point init(point: Point) { self.point = point } } let box = Box(point: Point(x: 1, y: 2))
Burada Point örneği heap'te saklanır çünkü Box sınıfına aittir.
Hikaye
Geliştirici, büyük yapıların her zaman stack'te yer alacağını düşünerek yapıların performansını optimize etmeye çalıştı ve koleksiyonların (Array, Dictionary) heap allocation kullandığını göz önünde bulundurmadığı için projede beklenmeyen bir bellek artışına neden oldu.
Hikaye
Projede closure'ın yapı değerlerini ele geçirdiği göz önünde bulundurulmadı, bu da heap'te yaşam süresinin etkiledi ve görünüm alanından çıktıklarında otomatik olarak serbest kalacakları beklentisini artırarak bellek sızıntılarına yol açtı.
Hikaye
Ağır yapıların dizilerini copy-on-write anlayışı olmadan kullanmak, koleksiyonları iş parçacıkları arasında iletmeyi gerektirdiğinden beklenmedik pahalı kopyalama işlemlerine yol açtı, bu da performansı düşürdü ve UI'de gecikmelere neden oldu.