Cihazımız temelde verilerimizi kaydettiği iki tür belleğe sahiptir:
- Disk belleği
- Rasgele Erişim Belleği (RAM)
Bir uygulamayı açtığımızda , sınıflarının tüm örneklerinin depolandığı bu uygulama için küçük bir RAM parçası ayrılır. Bu bellek parçasına Yığın bellek denir ve bu bellek yönetimi hakkında konuşurken bahsettiğimiz belleğin parçasıdır.
Yığın , belleğin (RAM) dinamik olarak ayrılmış belleğin bulunduğu bölümüdür
Yığın bellek çok sınırlı olduğundan, onu düzgün yönetmemiz çok önemlidir. Yetersiz bellek yönetimi, uygulamayı önemli ölçüde yavaşlatır ve er ya da geç bir çökmeye neden olur.
Peki swift yığın belleğini nasıl yönetir?
Swift, bellek yönetimi için Otomatik Referans Sayma (ARC) adı verilen bir şey kullanıyor . Bir sınıfın yeni bir nesnesi her oluşturulduğunda, ARC bu nesneyle ilişkili verileri depolamak için bir miktar bellek ayırır. Her nesne , kendisine güçlü bir referansı olan her şeyi izleyen bir referans sayma özelliğine sahip olacaktır . Her güçlü referans oluşturulduğunda, o nesnenin referans sayısı bir artar. Ve bir referans kapsam dışına çıktığında, referans sayısı bir azaltılır.
Ancak nesnelerin ayrımı nasıl kaldırılır?
Aşağıdaki gibi bir sınıf Mağaza örneğini ele alalım:
class Shop {
let name: String
init(name: String) {
self.name = name
}
}
Bir nesnenin, içinde bulunduğu ViewController kapsam dışına çıkması durumunda serbest bırakılacaktır. Bununla birlikte, nesne bir işlev içinde oluşturulursa, kapsamı yalnızca işlevin içinde olacaktır. İşlevin yürütülmesi tamamlandığında, nesnenin yeri kaldırılacaktır.
MyViewController adlı bir görünüm denetleyicimiz olduğunu ve viewDidLoad () yönteminde aşağıdaki gibi Shop sınıfının bir nesnesini oluşturduğumuzu varsayalım (bunun bir pasta dükkanı olduğunu varsayalım.
override func viewDidLoad() {
super.viewDidLoad()
let shop = Shop(name: “Sweet Tooth”)
}
Bu durumda, MyViewController kapsam dışına çıkmadığı sürece mağaza nesnesi kaldırılmayacaktır. Ancak runApp () işlevini aşağıdaki gibi tanımlarsak:
func runApp() {
let shop = Shop(name: “Sweet Tooth”)
}
Ve nesneyi orada oluşturmak yerine viewDidLoad () içinde runApp () 'yi çağırın, mağaza nesnesi runApp () kapsam dışına çıktığı anda serbest bırakılacaktır.
Şimdi, referans sayımı, nesneye yapılan referansları takip ederek, nesneye hala ihtiyaç olup olmadığını belirler. Referans sayısı sıfıra ulaşır ulaşmaz, nesnenin tahsisi kaldırılacak ve bu nesneyle ilişkili bellek başka bir nesne tarafından kullanılmak üzere serbest kalacaktır.
Peki bellek sızıntıları nasıl olur?
Bir içerik , yaşam döngüsü sona erdikten sonra bile bellekte kaldığında bir bellek sızıntısı meydana gelir .
Basit bir ifadeyle, bir bellek sızıntısı , temelde ayrılmış halde kalan, ancak hiç kullanılmayan bir bellek yığınıdır…
İki nesnenin yalnızca birbirine gönderme yaptığı ve başka hiçbir referansının olmadığı bir durumu hayal edelim. Her ikisi için de referans sayısı sıfır olamayacağından, ayrılamazlar ve hafızayı işgal etmeye devam edecekler. Bu, güçlü bir referans döngüsü veya bir tutma döngüsü olarak bilinir .
Bunun bir örneğini görelim. Cake sınıfını şu şekilde tanımlayalım:
class Cake {
let name: String
var soldBy: Shop?
init(name:String) {
self.name = name
}
}
Şimdi, aşağıdaki kod parçasını runApp () 'ye eklersek:
let cake = Cake(“Sweet Tooth Special Chocolate Truffle Cake”)
Bu bir Cake nesnesi yaratır. Ardından, Dükkan'a bir 'Cakes' niteliği ekleyin.
var cakes: [Cake] = []
fun sells(cake: Cake) {
self.cakes.append(cake)
item.soldBy = self
}
Şimdi runApp () 'de sells ()' i çağırırsak, bir tutma döngüsü yaratacaktır. Bu, bellek sızıntısına yol açacaktır .
Bu döngüyü kırmak için zayıf ve sahipsiz referanslar kullanıyoruz.
Güçsüz? Sahipsiz?
Saklama döngülerini kırmak için zayıf referanslardan yararlanıyoruz. Varsayılan olarak, swift'teki tüm referanslar güçlüdür ve oluşturulduktan sonra referans sayısını 1 artırır. Ancak zayıf referanslar referans sayısını etkilemez. Ayrıca, zayıf referanslar her zaman isteğe bağlı değişkenlerdir ve referans sayısı sıfır olduğunda, zayıf referans sıfıra ayarlanır .
Örneğimize geri dönersek ve Cake sınıfında 'soldBy' bildirimini şu şekilde değiştirin:
weak var soldBy: Shop?
runApp () 'de sells () çağrıldığında, alışverişe yönelik referans sayısı artmaz. Dolayısıyla, shop () 'a yapılan diğer tüm referanslar kaldırıldığında, boşaltılır ve kek için referans sayısı sıfır olur.
Zayıf referanslara benzer şekilde, sahipsiz referanslar bir nesnenin referans sayısını etkilemez. Ancak zayıf bir referansın aksine, sahipsiz referanslar asla isteğe bağlı değildir . Bu, zaten ayrılmamış bir nesneye işaret eden sahipsiz bir özelliğe erişmeye çalışırsanız, bu, sıfır olan isteğe bağlı bir değeri zorla açmak gibi olur.
Sahipsiz bir referansın yalnızca referans ve nesnenin aynı anda serbest bırakılacağından emin olması durumunda kullanılması önemlidir.
Öyleyse bekleyin… zayıf ve sahipsiz referanslar, birinin isteğe bağlı olduğu ve diğerinin olmadığı gerçeği dışında aynı…
Aslında, pek değil… Referans sayısından bahsettiğimizde, genellikle nesnenin güçlü referans sayısına atıfta bulunuruz . Benzer şekilde, swift , nesnenin sahipsiz referans sayısını ve zayıf referans sayılarını korur . Ancak zayıf referansı sahipsiz ve güçlü olmaktan ayıran şey, zayıf referansın nesnenin kendisinden ziyade " yan sehpa " olarak bilinen bir şeye işaret etmesidir . Bu nedenle, zayıf bir referans kapsam dışına çıktığında, nesne başlatılabilir ve serbest bırakılabilir… Zayıf referans nesneyi hiç göstermediği için. Güçlü referans sayısı sıfıra ulaştığında, nesne başlatılmamış olur, ancak sahipsiz referans sayısı sıfırdan fazlaysa serbest bırakılamaz.
Yan sehpa, nesnenin ek bilgilerini saklayan ayrı bir bellek öbeğidir. Bir nesnenin başlangıçta bir yan tablo girişi yoktur, nesne için zayıf bir referans oluşturulduğunda otomatik olarak oluşturulur.
Kapanmış referans döngüleri
Kapanışlar, bellek sızıntılarına yol açan referans döngülerine son vermenin başka bir yoludur. Bunu Dükkan sınıfı örneğimizle anlayalım. Shop sınıfımıza bir hesaplanmış özelliği cakeCount ekleyelim.
lazy var cakeCount: () -> Int {
self.cakes.count
}
Bu özelliği runApp () içinde kullanırsak, bir mağaza nesnesi hesaplanan cakeCount özelliği aracılığıyla kapanışı ifade eder ve kapanış nesneyi " self " aracılığıyla belirtir . Bu her iki yönde de güçlü bir referans olduğundan, bir tutma döngüsü yaratır.
Bu durumda, kapanışta kendine zayıf veya sahipsiz bir referansı yakalamak için Yakalama Listelerini aşağıdaki gibi kullanırız:
lazy var cakeCount: () -> Int { [weak self] in
self?.cakes.count
}
Artık kapanış referans sayısını etkilemiyor ve mağaza kapsam dışına çıkar çıkmaz kapanış da öyle.
Ve bu bir sargıdır. Bu, Swift'deki bellek yönetiminin temellerini kapsar. Bu makaleyi okuduğunuz için teşekkürler. Herhangi bir sorunuz memnuniyetle karşılanır ve geri bildirimler bizim için çok değerlidir, bu nedenle lütfen yorum bölümüne bir yorum bırakın.