Swift Dilinde Bellek Yönetimi – ARC

Her dilde olduğu gibi Swift dilinde de bellek yönetimi son derece önemlidir. Peki bellek yönetimi ne şekilde kontrol etmek doğru olur? Bu yazımda sizlere bunu en detaylı bir şekilde anlatmaya çalışacağım. Zaman kaybetmeden hemen başlayalım. Öncelikle olarak ARC nedir?

ARC, bir nesnenin ne zaman yaratıldığını, ne zaman kullanıldığını ve ne zaman bellekten atılması gerektiğini otomatik olarak izler. Her bir nesne için bir referans sayacı vardır. Bir nesne başka bir nesne veya değişken tarafından referans alındığında, referans sayısı artar. Nesne referansı bırakıldığında, referans sayısı azalır. Referans sayısı sıfıra indiğinde, ARC otomatik olarak nesnenin belleği serbest bırakır.

Yazımıza devam etmeden önce bir parantez bilgi. Swift dilinde 2 çeşit veri tipi vardır.

Ek Bilgi – Swift Veri Tipleri

Bellek yönetimini en doğru bir şekilde yapmak için Swift dilinde ne çeşit veri tipleri var bilmek gerekiyor.

  1. Reference Types
    • Class
    • Closure
  2. Value Types
    • Struct
    • Enum
    • Tuple
    • Array, Dictionary, Set
    • Basic Data Types: Int, Float, Double, Bool, String

Value tipleri stack’ler üzerinde saklanırken, referans tipleri heap üzerinde saklanr. Bu da şunu getirir bize, value tiplerin, değerini değiştirmenin, diğer kopyalarını etkilemeyeceği anlamına gelir. Referans türleri ise bellekte bir konumu gösterir ve birden fazla değişken aynı referansa sahip olabilir. Yani bir referans türü değişkeninin değerini değiştirdiğinizde, aynı referansa sahip diğer tüm değişkenlerin değeri de değişir.

Zaten bu sebeple ARC için önemli olan kavram Referans tipleridir. Biz bellek yönetimi için olan gerekli kavramları Class ve Closure için öğreneceğiz. Value tiplerde zaten böyle bir sıkıntı yok.

ARC Nasıl Çalışır?

class Person { let name: String init(name: String) { self.name = name print("\(name) is being initialized") } deinit { print("\(name) is being deinitialized") } } var reference1: Person? var reference2: Person? var reference3: Person? reference1 = Person(name: "John Appleseed") reference2 = reference1 reference3 = reference1 reference1 = nil

Yukarıda class olarak Person tanımladık. ve deinit metodunda da print olarak deinitialized olarak gerçekleşmesini görmek istiyoruz diyelim. Classdan 3 tane referans tipinde farklı objeler oluşturduk. İlk oluşturduğumuz referans tipini, diğer 2 referans tipine eşitledik. Buraya kadar bir sıkıntı yok, ancak sıkıntı reference1’i nil etmek istediğimizde karşımıza çıkıyor.

reference1’i nil yaptığımızda deinit metodu sadece 1 kez çalışmış oldu. Bu bizim istediğimiz bir senaryo değil referans2 ve referans3 hala referans1’i referans almaya devam ediyor. Oysa biz referans1’i nil yaptık bile çoktan.

Eğer diğer 2 tarafı nil yaparsak, her bir nil için deinit çalıştığını görmüş olacağız.

Bellek Yönetiminde Memory Leak Durumu

Belleğimizde referans olarak tutulan nesnemizin bellekte uzun süre kullanılmayıp ve bellekten çıkarılmadığı durumlarda başka bir referans nesnemizin bellekte işlem görememesi sonucu oluşan durumlardır. Yukarıda oluşturduğumuz örnekte ARC sayacı bu şekilde artmış oldu ve bir proje yavaş yavaş büyüdüğünde ise donmalar, kasmalar, kendi kendine uygulamanın kapanması gibi bir çok sonuca sebebiyet verecektir.

Strong Referanslar

Strong referans var olduğu sürece referansı alınan nesne bellekten silinmez. Örneğin, iki sınıf birbirine strong referans oluşturduğunda, bu sınıfların referans sayısı ARC ‘de sıfırlanmaz nillendiğinde ve bellekteki yerleri serbest bırakılamaz. Bir örnek ile açıklayım.

class NewPerson { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("\(name) is being deinitialized") } } class Apartment { let unit: String var tenant: NewPerson? init(unit: String) { self.unit = unit } deinit { print("\(unit) is being deinitialized") } } var john: NewPerson? var unit4A: Apartment? john = NewPerson(name: "John") unit4A = Apartment(unit: "4A") john?.apartment = unit4A unit4A?.tenant = john john = nil unit4A = nil

NewPerson ve Apartment adında 2 tane class oluşturduk. Kişinin apartman değişkenine, apartman class’ından üretilen bir obje bağlanırken, apartmanın tenant’ına da NewPerson’dan bir tane değişkeni bağladık.
Bu şekilde bağlam direk strong olarak birbirlerine bağlanmaktadır. Aşağıdaki ekran görüntüsünde görebileceğiniz gibi.

Ancak, birbirleri arasında atama yaptığımızda aralarında ki bağ strong olarak tanımlanacaktır.

Ve biz de objeleri nil yapmak istediğimizde aralarındaki bağı aşağıdaki ekran görüntüsünde ki koparamayacağız. Birbirleri arasında hala referans almaya devam etmektedirler.

Weak Referanslar

Weak referans, bir nesneye olan bağlantıyı güçlü (strong) bir şekilde tutmayan bir referans türüdür. Yani, weak referans, ARC (Automatic Reference Counting) tarafından izlenen bir nesnenin referans sayısını artırmaz. Bu sayede, weak referansı olan nesnenin sahipleri (strong referanslar) bellekten temizlendiğinde, weak referansı tutan nesne otomatik olarak nil olur. Bu, döngüsel referans problemlerini önlemeye yardımcı olabilir.

Swift dilinde, weak referanslar sadece Optional ve sınıf türleri için kullanılabilir. Yani, bir weak referans oluşturmak için var anahtar kelimesi ve ? işareti ile kullanılır.

class WeakPerson { let name: String var apartment: WeakApartment? init(name: String) { self.name = name } deinit { print("\(name) is being deinitialized") } } class WeakApartment { let unit: String weak var tenant: WeakPerson? init(unit: String) { self.unit = unit } deinit { print("\(unit) is being deinitialized") } } var weakjohn: WeakPerson? var weakUnit4A: WeakApartment? weakJohn = WeakPerson(name: "John") weakUnit4A = WeakApartment(unit: "4A") weakJohn?.apartment = weakUnit4A weakUnit4A?.tenant = weakJohn weakJohn = nil

Apartman içerisinde Person’u sadece weak olarak tanımladım. Bu durumda bağlantımız nasıl oldu?

Bu durumda eğer weakJohn’u nil yaparsak şöyle bir bağlantımız olacak

John objesini sildiğimizde hem John’un bağlantısını sildik hem de Apartman ile aralarındaki bağı koparmış olduk. Eğer weakJohn ile beraber weakUnit4A’yı da nil yapmak isteseydik, onun da deinit’e girdiğini göreceksiniz. Bunun en büyük sebebi aralarında bir bağ kalmamasıdır. Apartment’in başka tutunacak bir yeri kalmamıştır. Bu durumda da görsel şu şekilde olacaktır:

Örneğimizde sadece Apartman içerisinde ki Person’u nil yapmış olduk. Tam tersi olamaz mıydı, elbette ki oda olurdu. Aralarında ki bağı weak kurmamız yeterli sadece.

Unowned Referanslar

unowned referans, bir nesneye olan bağlantıyı weak referans gibi güçlü (strong) bir şekilde tutmayan fakat weak referanstan farklı olarak nil olamayan bir referans türüdür. Yani, unowned referans, ARC (Automatic Reference Counting) tarafından izlenen bir nesnenin referans sayısını artırmaz, fakat referansı tutan nesne serbest bırakıldığında otomatik olarak nil olmaz. Bir örnek üzerinde inceleyelim.

class Customer { let name: String var creditCard: CreditCard? init(name: String) { self.name = name } deinit { print("\(name) is being deinitialized") } } class CreditCard { let number: UInt64 unowned var customer: Customer init(number: UInt64, customer: Customer) { self.number = number self.customer = customer } deinit { print("\(number) is being deinitialized") } } var unownedJohn: Customer? unownedJohn = Customer(name: "unowned John") unownedJohn?.creditCard = CreditCard(number: 1234_5678_1234_5678, customer: unownedJohn!)

John objesini üretirken, CreditCard da ürettik aynı zamanda parametre alarak. Aralarındaki bağlantı şu şekilde olmaktadır:

Unowned bağlantıyı kopardığımızda bu şekilde, aynı weak de olduğu gibi strong bağlantısı kopacaktır.

Sonuç Olarak

Referans tiplerinde bu yazımda sizlere sınıflar üzerinde detaylı açıklamalar yaparak anlatmaya çalıştım. Aynı şekilde, closure örnekleri içinde bu örnekleri kullanmak mümkündür. Amaç aynı olduğu için tekrar üstünden geçmeye gerek görmedim. Fakat projelerinizde Memory Leak kullanımına oldukça dikkat etmeniz, hem kod kalitenizi daha da artıracak hem de uygulamanızı daha hızlı hale getirecektir.

Bol kodlamalar

Ömer Faruk Öztürk

Referans: Apple Swift Book – Automatic Reference Counting (ARC)

E-bültene Abone Ol Merak etmeyin. Spam yapmayacağız.

Yazar

İnsanların hayatlarına dokunan uygulamaları geliştirmeyi seven bir iOS yazılım geliştiricisi.

İlgili Yazılar

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Hızlı yorum için giriş yapın.

Kayıt Ol

VEYA

Zaten üye misiniz? Giriş Yap

Giriş Yap

VEYA

Henüz üyeliğiniz yok mu? Kayıt Ol