Strong Reference (güclü istinad): bu nədir, iş mexanizmi və ARC

Müəllif: IT Sectr Dərc olunub: 2026-03-30 Oxuma vaxtı: 9 dəq

Strong Reference (güclü istinad) — bu, obyektin yaddaşda qalmasını təmin edən standart yaddaş idarəetmə mexanizmidir, ona ən azı bir aktiv istinad göstərdikcə. Zəif istinadlardan fərqli olaraq, güclü istinad obyektin istinad sayğacını artırır və onun avtomatik azad olmasının qarşısını alır. Apple Developer Documentation-ya görə, ARC Swift və Objective-C-də obyektlərin həyat müddətini avtomatik idarə edir. Güclü istinadların işini başa düşmək mobil tətbiqlərdə yaddaş sızmalarının və siklik asılılıqların qarşısını almaq üçün kritik əhəmiyyət daşıyır.

Əsas məqamlar

  • Strong Reference — obyekti yaddaşda saxlayan, onun retain count-ni 1 artıran istinad.
  • ARC Swift və Objective-C-də əl ilə yaddaş idarəçiliyini aradan qaldıraraq avtomatik release və retain əməliyyatlarını daxil edir.
  • Retain cycle iki obyekt bir-birinə güclü istinadlar vasitəsilə istinad etdikdə yaranır — yaddaş heç vaxt azad edilmir.
  • Weak Reference istinad sayğacını artırmır və obyekt azad edildikdə avtomatik sıfırlanır.
  • Unowned Reference sayğacı artırmır, lakin obyektin sahibdən daha uzun yaşamadığını nəzərdə tutur.

Strong Reference nədir?

Strong Reference — bu, obyektin zibil yığan və ya yaddaş idarəetmə sistemi tərəfindən məhv edilməsinin qarşısını alan istinad növüdür. Obyektə ən azı bir güclü istinad mövcud olduqca, onun altındakı yaddaş azad edilmir. Bu, Swift və Objective-C-də ARC-nin və Java və Kotlin-də garbage collection-un əsasında duran əsas mexanizmdir.

Güclü istinad konsepsiyası avtomatik yaddaş idarəçiliyi olan bütün dillər üçün fundamental əhəmiyyət daşıyır. ARC olan sistemlərdə hər bir güclü istinad obyektin istinad sayğacını artırır. Sayğac sıfıra düşdükdə, obyekt dərhal dealokasiya edilir. Java və Kotlin-də garbage collector ilə güclü istinad obyektin əldə edilə bilən olduğunu və GC tərəfindən yığılmayacağını təmin edir.

WWDC 2021 məlumatlarına görə, iOS tətbiqlərində yaddaş sızmalarının təxminən 35%-i güclü istinadların düzgün istifadə edilməməsi və saxlama dövrləri ilə bağlıdır. Android inkişafında bağlanmalar və geri çağırışlarda gizli strong reference vasitəsilə sızmalar Context Leak-dan sonra yaddaş problemlərinin ikinci ən çox yayılmış səbəbidir.

Yaddaşla effektiv işləmək üçün strong, weak və unowned istinadları arasındakı fərqi başa düşmək və obyektlərin sahibliyi və həyat müddətindən asılı olaraq istinad növünü düzgün seçmək lazımdır.

ARC yaddaş idarəçiliyinə yanaşmanı necə dəyişdirdi

ARC tətbiq edilməzdən əvvəl tərtibatçılar hər bir obyekt üçün əl ilə retain və release çağırırdılar, bu da çoxsaylı səhvlərə səbəb olurdu. Apple tərəfindən 2011-ci ildə LLVM 3.0 buraxılışı ilə təqdim edilən ARC, kompilasiya mərhələsində sahiblik qrafikini təhlil edərək bu prosesi avtomatlaşdırdı. Kompilyator özü retain, release və autorelease çağırışlarını lazımi yerlərə daxil edir.

Clang Static Analyzer-ə görə, ARC-nin tətbiqi iOS tətbiqlərində yaddaşla bağlı səhvlərin sayını 70% azaldıb. Tərtibatçı üçün bu o deməkdir ki, yaddaş idarəçiliyi daha təhlükəsiz olub, lakin eyni zamanda güclü istinadların arxa planda necə işlədiyini başa düşmək zərurəti yaranıb — retain cycles-dən qaçmaq üçün.

Kotlin və Java-da ARC rolunu garbage collector yerinə yetirir, lakin güclü istinad prinsipi eyni qalır: GC Roots — bunlar obyektlərin güclü istinadlarla saxlandığı giriş nöqtələridir. Obyekt GC Root-dan güclü istinadlar zənciri ilə əldə edilə bildikcə, o yığılmayacaq.

Strong Reference ARC-də necə işləyir?

ARC (Automatic Reference Counting) yığındakı hər bir obyekt üçün istinadların sayılması prinsipi ilə işləyir. Obyektə yeni güclü istinad yaradıldıqda, sayğac artır (retain). İstinad məhv edildikdə və ya üzərinə yazıldıqda, sayğac azalır (release). Sayğac sıfıra çatdıqda, obyekt dərhal yaddaşdan silinir.

Swift-də bir nümunəyə baxaq. Sinif nümunəsi yaradılarkən ARC yaddaş ayırır və retain count-ni 1-ə bərabər qoyur. Hər yeni dəyişənə təyinat sayğacı artırır. Dəyişən görünmə sahəsindən çıxdıqda, sayğac azalır:

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

    func loadProfile() {
        // retain count = 1 yeni nümunə üçün
        let user = User(name: "Ivan")
        // retain count = 2 nameLabel təyin edildikdən sonra
        nameLabel = user.name
        // metoddan çıxış — user scope-dan çıxır, retain count = 1
    }
}

Bu kodda ARC User obyektinin yaddaşda qalmasını təmin edir, ona ən azı bir güclü istinad olduqca. loadProfile funksiyası başa çatdıqda, yerli user dəyişəni məhv edilir, lakin nameLabel hələ də obyekti saxlayır. Yaddaş yalnız nameLabel mövcud olmağı dayandırdıqda və ya üzərinə yazıldıqda azad ediləcək.

Kotlin-də oxşar davranış GC Roots vasitəsilə təmin edilir. Zibil yığanın kökündən (məsələn, statik sahə və ya aktiv thread) izlənilə bilən strong references zənciri mövcud olduqca, obyekt yaddaşda qalır. Fərq ondadır ki, GC yaddaşı dərhal azad etmir — bu, əldə edilə bilmə təhlilindən sonra asinxron şəkildə baş verir.

Yaddaş nə vaxt azad edilir

ARC-də azadetmə sayğac sıfırlandığı anda sinxron şəkildə baş verir. Swift və Objective-C-də obyektin nə vaxt silinəcəyini dəqiq bilirsiniz. Kotlin və Java-da azadetmə anı gözlənilməzdir, lakin bu, garbage collector səviyyəsində siklik asılılıqların aşkarlanmasının daha çevik sxemi ilə kompensasiya olunur.

Retain Cycles və yaddaş sızmaları

Retain cycle (saxlama dövrü) — iki və ya daha çox obyektin bir-birinə qarşılıqlı güclü istinadlara malik olduğu vəziyyətdir. Nəticədə onların retain count-ni heç vaxt sıfıra düşmür və obyektlər tətbiq üçün lazımsız hala gəlsələr belə, yaddaş azad edilmir.

Klassik nümunə: valideyn view controller uşaq obyekti güclü istinadla saxlayır, o da öz növbəsində valideyni güclü istinadla saxlayır. Bu, deleqatlar, bağlanmalar və iç-içə lambda ifadələri olan vəziyyətlər üçün xarakterikdir. Instruments Leaks-ə görə, retain cycles ARC istifadə edən tətbiqlərdə bütün yaddaş sızmalarının 60%-ə qədərini təşkil edir.

swift
class ParentViewController: UIViewController {
    var child: ChildViewController?

    func setupChild() {
        child = ChildViewController()
        // retain cycle: parent child-i saxlayır, child parent-i closure vasitəsilə saxlayır
        child?.onEvent = {
            self.handleEvent()
        }
    }

    func handleEvent() {}
}

Problem ondadır ki, onEvent bağlanması self-i (ParentViewController) güclü istinadla tutur, ParentViewController isə child-i güclü istinadla saxlayır. Hər iki obyekt heç vaxt azad edilməyəcək. Həll yolu — dövrü qırmaq üçün bağlanmada weak self istifadə etməkdir.

Kotlin-də oxşar dövrlər xarici obyektləri tutan lambdalardan istifadə edərkən yaranır. JVM garbage collector zamanla belə dövrləri aşkar edə bilər, ancaq obyektlər GC Roots-dan əldə edilə bilməz olduqda. Əgər dövr aktiv thread və ya UI konteksti ilə bağlıdırsa, sızma tətbiqin bütün ömrü boyu qalır.

Strong vs Weak vs Unowned Reference

İstinad növləri arasındakı fərqi başa düşmək təhlükəsiz yaddaş idarəçiliyinin açarıdır. Strong Reference retain count-ni artırır. Weak Reference retain count-ni artırmır və obyekt azad edildikdə avtomatik nil olur. Unowned Reference də retain count-ni artırmır, lakin sıfırlanmır — azad edildikdən sonra ona müraciət crash-ə səbəb olur.

İstinad növüRetain countTəhlükəsizlikNə vaxt istifadə olunmalı
Strong+1Təhlükəsiz (standart)Obyektə sahiblik, parent → child münasibəti
WeakDəyişmirAvtomatik sıfırlanma (safe)Deleqatlar, callback, geri istinadlar
UnownedDəyişmirGec müraciətdə crash riskiObyekt sahibdən daha uzun yaşamayacaqsa

İstinad növünün seçimi sahiblik münasibəti ilə müəyyən edilir. Əgər B obyekti A-nın hissəsidirsə və onsuz mövcud ola bilmirsə — Strong istifadə edin. Əgər B müstəqil mövcud ola bilirsə və bildirişlər üçün A-ya istinad edirsə — Weak istifadə edin. Unowned nadir hallarda tətbiq olunur — yalnız uşaq obyektin ömrü valideynin ömrünü qəti şəkildə aşmadıqda.

Seçim üçün praktik qayda

Apple Developer Documentation tövsiyə edir: standart olaraq bütün sahiblik münasibətləri üçün strong istifadə edin. Retain cycle-dən qaçmaq lazımdırsa — hansı istinadın zəif olmalı olduğunu müəyyən edin. Adətən bu, iyerarxiyada geri istinaddır (child → parent). Kotlin-də oxşar rol cache və observer nümunələri üçün tətbiq olunan java.lang.ref-dən WeakReference-ə aiddir.

Güclü istinad problemlərini necə düzəltmək olar

Retain cycles aşkarlanması — ilk addım. İkincisi — onların düzgün aradan qaldırılması. Güclü istinad dövrləri ilə mübarizənin əsas vasitəsi istinadlardan birini weak və ya unowned ilə əvəz etməkdir. Zibil yığımı olan dillərdə əlavə olaraq hər girişdən əvvəl əl ilə null yoxlaması ilə WeakReference tətbiq olunur.

Swift və Objective-C-də ən çox yayılmış düzəliş bağlanmalara [weak self] əlavə etməkdir. Bu, bağlanmanın obyekti azad edildikdən sonra saxlamamasını təmin edir. Kotlin-də oxşar məqsədlər üçün WeakReference sarğısı və ya onDestroy-də istinadın açıq təmizlənməsi istifadə olunur.

swift
class NetworkService {
    func fetchData(completion: @escaping (Data?) -> Void) {
        // weak self vasitəsilə tutma — retain cycle istisna edilib
        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 nümunədə [weak self] NetworkService-in artıq lazım olmadıqdan sonra bağlanma tərəfindən saxlanmamasını təmin edir. Əgər self sorğu tamamlanmadan əvvəl azad edilibsə — guard let self else { return } completion-i çağırmadan bağlanmadan çıxır.

Retain cycles diaqnostikası üçün iOS üçün Instruments Leaks və ya Android üçün Android Profiler + LeakCanary istifadə edin. Bu alətlər dəqiq saxlama qrafikini göstərir və obyektin azad edilməsinə hansı güclü istinadın mane olduğunu bildirir. Müntəzəm yaddaş profilləşdirməsi hər bir mobil layihənin CI/CD pipeline-ının bir hissəsi olmalıdır.

Swift və Kotlin-də Strong Reference — müqayisə

SwiftKotlin prinsipial olaraq fərqli yaddaş idarəetmə mexanizmlərindən istifadə edir, lakin güclü istinad konsepsiyası hər ikisində mövcuddur. Swift-də retain count = 0 olduqda sinxron azadetmə ilə ARC tətbiq olunur. Kotlin-də izləyən GC istifadə olunur, o, əldə edilə bilməyən obyektləri asinxron təmizləyir.

ParametrSwift (ARC)Kotlin (JVM GC)
Mexanizmİstinadların sayılması (retain count)Əldə edilə bilmənin izlənməsi (GC Roots)
AzadetməSinxron (sayğac sıfırlandıqda)Asinxron (GC dövrü ilə)
Retain cycleAvtomatik aşkarlanmırGC aşkar edə bilər, lakin dərhal deyil
Weak refweak (avtomatik sıfırlanma)WeakReference (əl ilə yoxlama)

Əsas praktik fərq: Swift-də retain cycle — zəmanətli sızmadır. Kotlin-də GC obyektlər kökdən əldə edilə bilməz olarsa, dövrü qıra bilər, lakin sızan obyektlərin ömrü gözlənilməz qalır. Buna görə hər iki dildə ən yaxşı strategiya dizayn mərhələsində güclü istinad dövrlərindən qaçmaqdır.

Swift üçün delegate nümunələrində və bağlanmalarda weak istifadə edin. Kotlin üçün — WeakReference və ya sahib məhv edildikdə istinadları avtomatik təmizləyən Lifecycle-aware komponentləri. Hər iki yanaşmada məqsəd birdir — qırılmaz saxlama zənciri yaratdıqları yerlərdə güclü istinadları istisna etmək.

Tez-tez verilən suallar

Strong Reference Weak Reference-dən nə ilə fərqlənir?

Strong Reference obyektin retain count-ni artırır və istinad mövcud olduqca onun azad edilməsinin qarşısını alır. Weak Reference retain count-ni dəyişmir və obyekt yaddaşdan silindikdə avtomatik sıfırlanır. Güclü istinadlar sahiblik üçün, zəif istinadlar isə geri əlaqələr və deleqatlar üçün istifadə olunur.

Retain cycle nədir və nə üçün təhlükəlidir?

Retain cycle — iki obyektin bir-birini güclü istinadlarla saxladığı qarşılıqlı blokadadır. Onların retain count-ni heç vaxt sıfıra düşmür, yaddaş azad edilmir. Bu, yaddaş sızmasına gətirib çıxarır: obyektlər əbədi olaraq yığında qalır, tətbiq getdikcə daha çox resurs istehlak edir və nəticədə OutOfMemory ilə çökür.

iOS tətbiqində retain cycle necə aşkar edilir?

Xcode-dan Instruments Leaks istifadə edin — Leaks şablonu ilə profilləşdirməyə başlayın, tətbiqdə ssenarini icra edin və sızma göstəricilərini yoxlayın. Dəqiq diaqnostika üçün Cycles & Roots sekmesine keçin — o, qırılmayan dövr təşkil edən qarşılıqlı strong reference qrafikini göstərəcək.

Nə vaxt Weak əvəzinə Unowned istifadə edilməlidir?

Unowned-dən uşaq obyektin ömrü valideynin ömrünü qəti şəkildə aşmadıqda istifadə edin — məsələn, obyekti ciddi şəkildə müəyyən edilmiş əhatə dairəsinə bağlayarkən. Şübhə varsa, Weak istifadə edin, çünki azad edilmiş unowned-a müraciət tətbiqin çökməsinə səbəb olur.

Güclü istinadlar tətbiqin performansına təsir edirmi?

Dolayı yolla — bəli. ARC-də hər bir retain və release əlavə xərcləri olan atomik əməliyyatdır. Dövrlərdə çox sayda obyekt olduqda bu, performansa təsir edə bilər. Lakin əsas problem ARC-nin iş sürəti deyil, səhv seçilmiş istinad növü səbəbindən yaddaş sızmalarıdır.

Nəticə

  • Strong Reference — obyektə sahibliyin əsas mexanizmi, onu retain count artırmaqla yaddaşda saxlayır.
  • ARC Swift və Objective-C-də yaddaş idarəçiliyini avtomatlaşdırır, əl ilə retain və release-i aradan qaldırır, lakin retain cycles-dən qorumur.
  • Retain cycle qarşılıqlı güclü istinadlar zamanı yaranır — bu, ARC sistemlərində yaddaş sızmalarının əsas səbəbidir.
  • WeakUnowned istinadlar retain count-ni artırmadan güclü istinad dövrlərini qırır.
  • İstinad növünün seçimi sahiblik münasibəti ilə müəyyən edilir: parent→child üçün Strong, child→parent üçün Weak və ya Unowned.
  • Instruments LeaksLeakCanary — iOS və Android-də problemli güclü istinadları aşkar etmək üçün əsas alətlər.
  • Sahiblik qrafikini əvvəlcədən layihələndirin — bu, tətbiq buraxılışından sonra yaddaş sızmalarını düzəltməkdən daha ucuzdur.

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun