Strong Reference (güçlü referans): nedir, çalışma mekanizması ve ARC

Yazar: IT Sectr Yayınlanma: 2026-03-30 Okuma süresi: 9 dk

Strong Reference (güçlü referans), bir nesnenin en az bir aktif referans tarafından gösterildiği sürece bellekte kaldığı standart bir bellek yönetimi mekanizmasıdır. Zayıf referansların aksine, güçlü bir referans nesnenin referans sayacını artırır ve otomatik olarak serbest bırakılmasını engeller. Apple Developer Documentation'a göre ARC, Swift ve Objective-C'de nesnelerin yaşam döngüsünü otomatik olarak yönetir. Mobil uygulamalarda bellek sızıntılarını ve döngüsel bağımlılıkları önlemek için güçlü referansların çalışmasını anlamak kritik öneme sahiptir.

Önemli noktalar

  • Strong Reference — retain count'u 1 artırarak nesneyi bellekte tutan bir referanstır.
  • ARC otomatik olarak retain ve release işlemlerini ekler, Swift ve Objective-C'de manuel bellek yönetimini ortadan kaldırır.
  • Retain cycle, iki nesnenin birbirini güçlü referanslarla referans göstermesiyle oluşur — bellek asla serbest bırakılmaz.
  • Weak Reference referans sayacını artırmaz ve nesne serbest bırakıldığında otomatik olarak nil olur.
  • Unowned Reference sayacı artırmaz ancak nesnenin sahibinden daha uzun yaşamadığını varsayar.

Strong Reference Nedir?

Strong Reference, bir nesnenin çöp toplayıcı veya bellek yönetim sistemi tarafından yok edilmesini önleyen bir referans türüdür. Nesneye en az bir güçlü referans olduğu sürece, belleği serbest bırakılmaz. Bu, Swift ve Objective-C'de ARC ile Java ve Kotlin'de çöp toplamanın temelini oluşturan mekanizmadır.

Güçlü referans kavramı, otomatik bellek yönetimine sahip tüm diller için temeldir. ARC'li sistemlerde, her güçlü referans nesnenin referans sayacını artırır. Sayaç sıfıra düştüğünde, nesne hemen serbest bırakılır. Java ve Kotlin'de çöp toplama ile güçlü bir referans, nesnenin erişilebilir olduğunu ve GC tarafından toplanmayacağını garanti eder.

WWDC 2021'e göre, iOS uygulamalarındaki bellek sızıntılarının yaklaşık %35'i, güçlü referansların yanlış kullanımı ve retain cycle'lar ile ilgilidir. Android geliştirmede, closure'lar ve callback'lerdeki örtük güçlü referanslar yoluyla sızıntılar, Context Leak'ten sonra en sık görülen ikinci bellek sorunu nedenidir.

Bellekle etkili bir şekilde çalışmak için strong, weak ve unowned referansları arasındaki farkı anlamanız ve sahiplik ve nesne yaşam süresine göre doğru referans türünü seçmeniz gerekir.

ARC Bellek Yönetimini Nasıl Değiştirdi?

ARC'den önce geliştiriciler her nesne için manuel olarak retain ve release çağırmak zorundaydı ve bu da çok sayıda hataya yol açıyordu. Apple tarafından 2011 yılında LLVM 3.0 ile tanıtılan ARC, derleme zamanında sahiplik grafiğini analiz ederek bu süreci otomatikleştirdi. Derleyicinin kendisi, gerekli yerlerde retain, release ve autorelease çağrılarını ekler.

Clang Static Analyzer'a göre, ARC'nin tanıtılması iOS uygulamalarındaki bellek ile ilgili hataları %70 oranında azalttı. Geliştiriciler için bu, bellek yönetiminin daha güvenli hale geldiği, ancak aynı zamanda retain cycle'lardan kaçınmak için güçlü referansların perde arkasında nasıl çalıştığını anlama ihtiyacının doğduğu anlamına gelir.

Kotlin ve Java'da, çöp toplayıcı ARC'nin rolünü oynar, ancak güçlü referans ilkesi aynı kalır: GC Roots, nesnelerin güçlü referanslarla tutulduğu giriş noktalarıdır. Bir nesne, bir GC Root'tan güçlü referans zinciri aracılığıyla erişilebilir olduğu sürece, toplanmayacaktır.

ARC'de Strong Reference Nasıl Çalışır?

ARC (Automatic Reference Counting), yığındaki her nesne için referansları sayarak çalışır. Bir nesneye yeni bir güçlü referans oluşturulduğunda, sayaç artar (retain). Referans yok edildiğinde veya üzerine yazıldığında, sayaç azalır (release). Sayaç sıfıra ulaştığında, nesne derhal bellekten kaldırılır.

Swift'te bir örnek düşünelim. Bir sınıf örneği oluşturulduğunda, ARC bellek ayırır ve retain count'u 1 olarak ayarlar. Başka bir değişkene her yeni atama sayacı artırır. Değişken kapsam dışına çıktığında, sayaç azalır:

swift
class ProfileViewController {
    var nameLabel: String?
    var avatarImage: UIImage?

    func loadProfile() {
        // yeni örnek için retain count = 1
        let user = User(name: "Ivan")
        // nameLabel atandıktan sonra retain count = 2
        nameLabel = user.name
        // metottan çıkış — user kapsam dışına çıkar, retain count = 1
    }
}

Bu kodda ARC, User nesnesine en az bir güçlü referans olduğu sürece bellekte kalmasını sağlar. loadProfile işlevi sona erdiğinde, yerel user değişkeni yok edilir, ancak nameLabel hala nesneyi tutar. Bellek yalnızca nameLabel'in varlığı sona erdiğinde veya üzerine yazıldığında serbest bırakılır.

Kotlin'de benzer bir davranış GC Roots aracılığıyla sağlanır. Bir çöp toplayıcı kökünden (orneğin, statik bir alan veya aktif bir iş parçacığı) izlenebilir bir güçlü referans zinciri olduğu sürece, nesne bellekte kalır. Fark, GC'nin belleği anında serbest bırakmamasıdır — bu, erişilebilirlik analizinden sonra eşzamansız olarak gerçekleşir.

Bellek Serbest Bırakma Ne Zaman Gerçekleşir?

ARC'de, serbest bırakma sayaç sıfıra ulaştığında eşzamanlı olarak gerçekleşir. Swift ve Objective-C'de, nesnenin ne zaman kaldırılacağını tam olarak bilirsiniz. Kotlin ve Java'da, serbest bırakma anı öngörülemez, ancak bu, çöp toplayıcı düzeyinde döngüsel bağımlılıkları tespit etmek için daha esnek bir şema ile telafi edilir.

Retain Cycles ve Bellek Sızıntıları

Retain cycle (tutma döngüsü) — iki veya daha fazla nesnenin birbirine karşılıklı güçlü referanslara sahip olduğu bir durumdur. Sonuç olarak, retain count'ları asla sıfıra düşmez ve nesneler uygulama için artık gerekli olmasa bile bellek asla serbest bırakılmaz.

Klasik bir örnek: bir üst görünüm denetleyicisi, güçlü bir referansla alt nesneyi tutar ve alt nesne de güçlü bir referansla üst nesneyi tutar. Bu, delegeler, closure'lar ve iç içe lambda ifadeleri olan durumlarda tipiktir. Instruments Leaks'e göre, retain cycle'lar ARC kullanan uygulamalardaki tüm bellek sızıntılarının %60'ına kadarını oluşturur.

swift
class ParentViewController: UIViewController {
    var child: ChildViewController?

    func setupChild() {
        child = ChildViewController()
        // retain cycle: ebeveyn çocuğu tutar, çocuk closure aracılığıyla ebeveyni tutar
        child?.onEvent = {
            self.handleEvent()
        }
    }

    func handleEvent() {}
}

Buradaki sorun, onEvent closure'ının self'i (ParentViewController) güçlü bir referansla yakalaması ve ParentViewController'ın kendisinin child'ı güçlü bir referansla tutmasıdır. Her iki nesne de asla serbest bırakılmayacaktır. Çözüm, döngüyü kırmak için closure'da weak self kullanmaktır.

Kotlin'de, dış nesneleri yakalayan lambdalar kullanıldığında benzer döngüler ortaya çıkar. JVM çöp toplayıcısı, zaman içinde bu tür döngüleri tespit edebilir, ancak yalnızca nesneler GC Roots'tan erişilemezse. Döngü aktif bir iş parçacığına veya UI bağlamına bağlıysa, sızıntı uygulamanın tüm ömrü boyunca devam eder.

Strong vs Weak vs Unowned Reference

Referans türleri arasındaki farkı anlamak, güvenli bellek yönetiminin anahtarıdır. Strong Reference retain count'u artırır. Weak Reference retain count'u artırmaz ve nesne serbest bırakıldığında otomatik olarak nil olur. Unowned Reference da retain count'u artırmaz ancak sıfırlanmaz — serbest bırakıldıktan sonra ona erişmek çökmeye neden olur.

Referans TürüRetain countGüvenlikNe Zaman Kullanılmalı
Strong+1Güvenli (varsayılan)Nesne sahipliği, ebeveyn → çocuk ilişkisi
WeakDeğiştirmezOtomatik sıfırlama (güvenli)Delegeler, callbacks, ters referanslar
UnownedDeğiştirmezGeç erişimde çökme riskiNesnenin sahibinden daha uzun yaşaması garanti edildiğinde

Referans türü seçimi, sahiplik ilişkisi tarafından belirlenir. B nesnesi A'nın bir parçasıysa ve onsuz var olamıyorsa — Strong kullanın. B bağımsız olarak var olabiliyor ve bildirimler için A'ya referans veriyorsa — Weak kullanın. Unowned nadiren kullanılır — yalnızca alt nesnenin ömrü üst nesneninkini aşmadığında.

Pratik Seçim Kuralı

Apple Developer Documentation şunu önerir: varsayılan olarak, tüm sahiplik ilişkileri için strong kullanın. Bir retain cycle'dan kaçınmanız gerekiyorsa — hangi referansın zayıf olması gerektiğini belirleyin. Genellikle bu, hiyerarşideki ters referanstır (çocuk → ebeveyn). Kotlin'de, java.lang.ref'teki WeakReference benzer bir rol oynar ve önbellekler ve observer desenleri için kullanılır.

Güçlü Referans Sorunları Nasıl Çözülür

Retain cycle'ları tespit etmek ilk adımdır. İkincisi, onları doğru şekilde ortadan kaldırmaktır. Güçlü referans döngülerini kırmanın ana aracı, referanslardan birini weak veya unowned ile değiştirmektir. Çöp toplamalı dillerde, her erişimden önce manuel null denetimi ile WeakReference ek olarak kullanılır.

Swift ve Objective-C'de en yaygın düzeltme, closure'lara [weak self] eklemektir. Bu, closure'ın nesneyi serbest bırakıldıktan sonra tutmamasını sağlar. Kotlin'de, benzer amaçlar için WeakReference sarmalayıcıları veya onDestroy'de açık referans temizliği kullanılır.

swift
class NetworkService {
    func fetchData(completion: @escaping (Data?) -> Void) {
        // weak self ile yakalama — retain cycle ortadan kaldırıldı
        URLSession.shared.dataTask(
            with: URL(string: "https://api.example.com")!
        ) { [weak self] data, response, error in
            guard let self else { return }
            completion(data)
        }.resume()
    }
}

Bu örnekte, [weak self] NetworkService'in artık gerekli olmadığında closure tarafından tutulmamasını sağlar. İstek tamamlanmadan önce self serbest bırakılırsa — guard let self else { return } completion'ı çağırmadan closure'dan çıkar.

Retain cycle teşhisi için iOS için Instruments Leaks veya Android için Android Profiler + LeakCanary kullanın. Bu araçlar tam tutma grafiğini gösterir ve hangi güçlü referansın nesnenin serbest bırakılmasını engellediğini belirtir. Düzenli bellek profili oluşturma, herhangi bir mobil projenin CI/CD boru hattının bir parçası olmalıdır.

Swift ve Kotlin'de Strong Reference — Karşılaştırma

Swift ve Kotlin temelde farklı bellek yönetim mekanizmaları kullanır, ancak güçlü referans kavramı her ikisinde de mevcuttur. Swift, retain count = 0'da eşzamanlı serbest bırakma ile ARC kullanır. Kotlin, erişilemeyen nesneleri eşzamansız olarak temizleyen bir izleme GC'si kullanır.

ParametreSwift (ARC)Kotlin (JVM GC)
MekanizmaReferans sayma (retain count)Erişilebilirlik izleme (GC Roots)
Serbest bırakmaEşzamanlı (sayaç sıfıra ulaştığında)Eşzamansız (GC döngüsüyle)
Retain cycleOtomatik olarak algılanmazGC algılayabilir, ancak hemen değil
Zayıf refweak (otomatik sıfırlama)WeakReference (manuel denetim)

Ana pratik fark: Swift'te retain cycle kesin bir sızıntıdır. Kotlin'de, nesneler kökten erişilemezse GC döngüyü kırabilir, ancak sızıntı yapan nesnelerin ömrü öngörülemez kalır. Bu nedenle, her iki dilde de en iyi strateji, tasarım aşamasında güçlü referans döngülerinden kaçınmaktır.

Swift için, temsilci desenlerinde ve closure'larda weak kullanın. Kotlin için, sahibi yok edildiğinde referansları otomatik olarak temizleyen WeakReference veya Lifecycle-aware bileşenlerini kullanın. Her iki yaklaşımda da amaç aynıdır — kırılmaz bir tutma zinciri oluşturdukları yerlerde güçlü referansları ortadan kaldırmak.

Sıkça Sorulan Sorular

Strong Reference, Weak Reference'den nasıl farklıdır?

Strong Reference nesnenin retain count'unu artırır ve referans var olduğu sürece serbest bırakılmasını engeller. Weak Reference retain count'u değiştirmez ve nesne bellekten kaldırıldığında otomatik olarak nil olur. Güçlü referanslar sahiplik için, zayıf referanslar ters bağlantılar ve delegeler için kullanılır.

Retain cycle nedir ve neden tehlikelidir?

Retain cycle — iki nesnenin birbirini güçlü referanslarla tuttuğu karşılıklı bir kilittir. Retain count'ları asla sıfıra düşmez, bellek serbest bırakılmaz. Bu, bellek sızıntılarına yol açar: nesneler sonsuza kadar yığında kalır, uygulama giderek daha fazla kaynak tüketir ve sonunda OutOfMemory ile çöker.

Bir iOS uygulamasında retain cycle nasıl tespit edilir?

Xcode'dan Instruments Leaks kullanın — Leaks şablonuyla profilleme çalıştırın, uygulamada bir senaryo yürütün ve sızıntı göstergelerini kontrol edin. Kesin teşhis için Cycles & Roots sekmesine geçin — kırılmaz bir döngü oluşturan karşılıklı güçlü referansların grafiğini gösterir.

Weak yerine Unowned ne zaman kullanılmalıdır?

Unowned, alt nesnenin ömrünün üst nesneninkini aşmadığı garanti edildiğinde kullanılmalıdır — örneğin, bir nesneyi kesin olarak tanımlanmış bir kapsama bağlarken. Şüpheniz varsa, Weak kullanın, çünkü serbest bırakılmış bir unowned referansına erişmek uygulamanın çökmesine neden olur.

Güçlü referanslar uygulama performansını etkiler mi?

Dolaylı olarak — evet. ARC'deki her retain ve release ek yükü olan atomik bir işlemdir. Döngülerde çok sayıda nesne varsa, bu performansı etkileyebilir. Ancak ana sorun ARC'nin hızı değil, yanlış seçilmiş bir referans türü nedeniyle oluşan bellek sızıntılarıdır.

Özet

  • Strong Reference, retain count'u artırarak nesneyi bellekte tutan temel nesne sahipliği mekanizmasıdır.
  • ARC, Swift ve Objective-C'de bellek yönetimini otomatikleştirir, manuel retain ve release'i ortadan kaldırır, ancak retain cycle'lara karşı korumaz.
  • Retain cycle karşılıklı güçlü referanslarla oluşur — ARC sistemlerinde bellek sızıntılarının ana nedenidir.
  • Weak ve Unowned referansları, retain count'u artırmadan güçlü referans döngülerini kırar.
  • Referans türü seçimi sahiplik ilişkisine göre belirlenir: ebeveyn→çocuk için Strong, çocuk→ebeveyn için Weak veya Unowned.
  • Instruments Leaks ve LeakCanary, iOS ve Android'de sorunlu güçlü referansları tespit etmek için ana araçlardır.
  • Sahiplik grafiğini önceden tasarlayın — uygulama yayınlandıktan sonra bellek sızıntılarını düzeltmekten daha ucuzdur.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun