Strong Reference (مرجع قوی): چیست، مکانیزم کار و ARC

نویسنده: IT Sectr منتشر شده: 2026-03-30 زمان مطالعه: 9 دقیقه

Strong Reference (مرجع قوی) — یک مکانیزم استاندارد مدیریت حافظه است که در آن شیء تا زمانی که حداقل یک مرجع فعال به آن اشاره می‌کند در حافظه باقی می‌ماند. برخلاف مراجع ضعیف، مرجع قوی شمارنده مراجع شیء را افزایش می‌دهد و از آزادسازی خودکار آن جلوگیری می‌کند. به گفته Apple Developer Documentation، ARC به طور خودکار عمر اشیاء را در Swift و Objective-C مدیریت می‌کند. درک کار مراجع قوی برای جلوگیری از نشت حافظه و وابستگی‌های چرخه‌ای در برنامه‌های موبایل حیاتی است.

نکات اصلی

  • Strong Reference — مرجعی که شیء را در حافظه نگه می‌دارد و retain count آن را ۱ افزایش می‌دهد.
  • ARC به طور خودکار عملیات release و retain را درج می‌کند و مدیریت دستی حافظه را در Swift و Objective-C حذف می‌کند.
  • Retain cycle زمانی رخ می‌دهد که دو شیء از طریق مراجع قوی به یکدیگر ارجاع دهند — حافظه هرگز آزاد نمی‌شود.
  • Weak Reference شمارنده مراجع را افزایش نمی‌دهد و هنگام آزادسازی شیء به طور خودکار صفر می‌شود.
  • Unowned Reference شمارنده را افزایش نمی‌دهد، اما فرض می‌کند که شیء بیشتر از مالک زنده نمی‌ماند.

Strong Reference چیست؟

Strong Reference — نوعی مرجع به شیء است که از نابودی آن توسط جمع‌آورنده زباله یا سیستم مدیریت حافظه جلوگیری می‌کند. تا زمانی که حداقل یک مرجع قوی به شیء وجود دارد، حافظه زیر آن آزاد نمی‌شود. این مکانیزم پایه‌ای است که ARC در Swift و Objective-C و جمع‌آوری زباله در Java و Kotlin بر آن ساخته شده‌اند.

مفهوم مرجع قوی برای تمام زبان‌های دارای مدیریت خودکار حافظه اساسی است. در سیستم‌های دارای ARC هر مرجع قوی شمارنده مراجع شیء را افزایش می‌دهد. هنگامی که شمارنده به صفر می‌رسد، شیء بلافاصله از حافظه خارج می‌شود. در Java و Kotlin با جمع‌آورنده زباله، مرجع قوی تضمین می‌کند که شیء قابل دسترسی است و توسط GC جمع‌آوری نخواهد شد.

طبق داده‌های WWDC 2021، حدود ۳۵٪ از نشت‌های حافظه در برنامه‌های iOS به استفاده نادرست از مراجع قوی و چرخه‌های نگهداری مرتبط است. در توسعه Android، نشت‌ها از طریق strong reference ضمنی در بستارها و فراخوانی‌های بازگشتی دومین علت شایع مشکلات حافظه پس از Context Leak است.

برای کار مؤثر با حافظه لازم است تفاوت بین مراجع strong، weak و unowned را درک کرده و بسته به مالکیت و عمر اشیاء، نوع مرجع را به درستی انتخاب کنید.

چگونه ARC رویکرد مدیریت حافظه را تغییر داد

قبل از معرفی ARC، توسعه‌دهندگان به صورت دستی retain و release را برای هر شیء فراخوانی می‌کردند که منجر به اشتباهات متعددی می‌شد. ARC که توسط اپل در سال ۲۰۱۱ با انتشار LLVM 3.0 معرفی شد، این فرآیند را با تحلیل گراف مالکیت در مرحله کامپایل خودکار کرد. کامپایلر خود فراخوانی‌های retain، release و autorelease را در مکان‌های مناسب درج می‌کند.

طبق Clang Static Analyzer، معرفی ARC تعداد باگ‌های مرتبط با حافظه در برنامه‌های iOS را ۷۰٪ کاهش داد. برای توسعه‌دهنده این به معنای ایمن‌تر شدن مدیریت حافظه است، اما همزمان نیاز به درک نحوه کار مراجع قوی در پشت صحنه — برای اجتناب از retain cycles — ایجاد شد.

در Kotlin و Java نقش ARC را جمع‌آورنده زباله ایفا می‌کند، اما اصل مرجع قوی یکسان باقی می‌ماند: GC Roots — نقاط ورودی هستند که از طریق آنها اشیاء توسط مراجع قوی نگهداری می‌شوند. تا زمانی که شیء از طریق زنجیره مراجع قوی از GC Root قابل دسترسی باشد، جمع‌آوری نخواهد شد.

Strong Reference در ARC چگونه کار می‌کند؟

ARC (Automatic Reference Counting) بر اساس اصل شمارش مراجع برای هر شیء در heap کار می‌کند. هنگامی که یک مرجع قوی جدید به شیء ایجاد می‌شود، شمارنده افزایش می‌یابد (retain). هنگامی که مرجع نابود یا بازنویسی می‌شود، شمارنده کاهش می‌یابد (release). هنگامی که شمارنده به صفر می‌رسد، شیء بلافاصله از حافظه حذف می‌شود.

مثالی در Swift را در نظر بگیرید. هنگام ایجاد یک نمونه از کلاس، ARC حافظه را تخصیص می‌دهد و retain count را برابر ۱ قرار می‌دهد. هر تخصیص جدید به متغیر دیگر شمارنده را افزایش می‌دهد. هنگامی که متغیر از محدوده دید خارج می‌شود، شمارنده کاهش می‌یابد:

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

    func loadProfile() {
        // retain count = 1 برای نمونه جدید
        let user = User(name: "Ivan")
        // retain count = 2 پس از تخصیص nameLabel
        nameLabel = user.name
        // خروج از متد — user از scope خارج می‌شود، retain count = 1
    }
}

در این کد ARC تضمین می‌کند که شیء User تا زمانی که حداقل یک مرجع قوی به آن وجود دارد در حافظه باقی می‌ماند. هنگامی که تابع loadProfile پایان می‌یابد، متغیر محلی user نابود می‌شود، اما nameLabel همچنان شیء را نگه می‌دارد. حافظه تنها زمانی آزاد می‌شود که nameLabel از بین برود یا بازنویسی شود.

در Kotlin رفتار مشابه از طریق GC Roots تضمین می‌شود. تا زمانی که یک زنجیره قابل ردیابی از strong references از ریشه جمع‌آورنده زباله (مثلاً فیلد ایستا یا نخ فعال) وجود دارد، شیء در حافظه باقی می‌ماند. تفاوت در این است که GC حافظه را فوراً آزاد نمی‌کند — این کار به صورت ناهمزمان پس از تحلیل دسترسی‌پذیری انجام می‌شود.

زمان آزادسازی حافظه

در ARC آزادسازی به صورت همزمان در لحظه صفر شدن شمارنده رخ می‌دهد. در Swift و Objective-C دقیقاً می‌دانید شیء چه زمانی حذف خواهد شد. در Kotlin و Java لحظه آزادسازی غیرقابل پیش‌بینی است، اما این با طرح انعطاف‌پذیرتر تشخیص وابستگی‌های چرخه‌ای در سطح جمع‌آورنده زباله جبران می‌شود.

Retain Cycles و نشت حافظه

Retain cycle (چرخه نگهداری) — وضعیتی است که در آن دو یا چند شیء دارای مراجع قوی متقابل به یکدیگر هستند. در نتیجه retain count آنها هرگز به صفر نمی‌رسد و حافظه حتی پس از بی‌نیازی برنامه از اشیاء آزاد نمی‌شود.

مثال کلاسیک: view controller والد، شیء فرزند را با مرجع قوی نگه می‌دارد و آن نیز به نوبه خود والد را با مرجع قوی نگه می‌دارد. این برای موقعیت‌های دارای delegate، بستارها و عبارات lambda تو در تو معمول است. طبق Instruments Leaks، retain cycles تا ۶۰٪ از کل نشت‌های حافظه در برنامه‌های استفاده‌کننده از ARC را تشکیل می‌دهند.

swift
class ParentViewController: UIViewController {
    var child: ChildViewController?

    func setupChild() {
        child = ChildViewController()
        // retain cycle: parent child را نگه می‌دارد، child parent را از طریق closure نگه می‌دارد
        child?.onEvent = {
            self.handleEvent()
        }
    }

    func handleEvent() {}
}

مشکل اینجاست که بستار onEvent self (ParentViewController) را با مرجع قوی می‌گیرد و خود ParentViewController child را با مرجع قوی نگه می‌دارد. هر دو شیء هرگز آزاد نخواهند شد. راه حل — استفاده از weak self در بستار برای شکستن چرخه.

در Kotlin چرخه‌های مشابه هنگام استفاده از لامبداهایی که اشیاء خارجی را می‌گیرند ایجاد می‌شود. جمع‌آورنده زباله JVM ممکن است به مرور چنین چرخه‌هایی را تشخیص دهد، اما فقط اگر اشیاء از GC Roots غیرقابل دسترسی باشند. اگر چرخه با یک نخ فعال یا زمینه UI مرتبط باشد، نشت تا طول عمر برنامه باقی می‌ماند.

Strong vs Weak vs Unowned Reference

درک تفاوت بین انواع مراجع — کلید مدیریت ایمن حافظه است. Strong Reference retain count را افزایش می‌دهد. Weak Reference retain count را افزایش نمی‌دهد و هنگام آزادسازی شیء به طور خودکار nil می‌شود. Unowned Reference نیز retain count را افزایش نمی‌دهد، اما صفر نمی‌شود — مراجعه به آن پس از آزادسازی باعث crash می‌شود.

نوع مرجعRetain countایمنیزمان استفاده
Strong+1ایمن (پیش‌فرض)مالکیت شیء، رابطه parent ← child
Weakتغییر نمی‌دهدصفر شدن خودکار (safe)Delegateها، callback، مراجع بازگشتی
Unownedتغییر نمی‌دهدریسک crash در مراجعه دیرهنگاموقتی شیء تضمیناً بیشتر از مالک زنده نیست

انتخاب نوع مرجع با رابطه مالکیت تعیین می‌شود. اگر شیء B بخشی از A است و بدون آن نمی‌تواند وجود داشته باشد — از Strong استفاده کنید. اگر B می‌تواند مستقل وجود داشته باشد و برای اعلان‌ها به A ارجاع می‌دهد — از Weak استفاده کنید. Unowned به ندرت استفاده می‌شود — فقط زمانی که عمر شیء فرزند به طور قطع از عمر والد تجاوز نمی‌کند.

قاعده عملی انتخاب

Apple Developer Documentation توصیه می‌کند: به طور پیش‌فرض برای تمام روابط مالکیت از strong استفاده کنید. اگر نیاز به اجتناب از retain cycle دارید — تعیین کنید کدام مرجع باید ضعیف باشد. معمولاً این مرجع بازگشتی در سلسله‌مراتب است (child ← parent). در Kotlin نقش مشابهی به WeakReference از java.lang.ref داده می‌شود که برای کش‌ها و الگوی observer استفاده می‌شود.

چگونه مشکلات مراجع قوی را برطرف کنیم

تشخیص retain cycles — گام اول. گام دوم — رفع صحیح آنها. ابزار اصلی مبارزه با چرخه‌های مراجع قوی، جایگزینی یکی از مراجع با weak یا unowned است. در زبان‌های دارای جمع‌آوری زباله، علاوه بر این از WeakReference با بررسی دستی null قبل از هر دسترسی استفاده می‌شود.

در Swift و Objective-C رایج‌ترین رفع، افزودن [weak self] در بستارها است. این تضمین می‌کند که بستار شیء را پس از آزادسازی آن نگه نمی‌دارد. در Kotlin برای اهداف مشابه از wrapper WeakReference یا پاکسازی صریح مرجع در onDestroy استفاده می‌شود.

swift
class NetworkService {
    func fetchData(completion: @escaping (Data?) -> Void) {
        // گرفتن از طریق weak self — retain cycle حذف شد
        URLSession.shared.dataTask(
            with: URL(string: "https://api.example.com")!
        ) { [weak self] data, response, error in
            guard let self else { return }
            completion(data)
        }.resume()
    }
}

در این مثال [weak self] تضمین می‌کند که NetworkService توسط بستار پس از عدم نیاز نگه داشته نمی‌شود. اگر self قبل از تکمیل درخواست آزاد شده باشد — guard let self else { return } بدون فراخوانی completion از بستار خارج می‌شود.

برای تشخیص retain cycles از Instruments Leaks برای iOS یا Android Profiler + LeakCanary برای Android استفاده کنید. این ابزارها گراف دقیق نگهداری را نشان می‌دهند و مشخص می‌کنند کدام مرجع قوی مانع آزادسازی شیء می‌شود. پروفایل‌گیری منظم حافظه باید بخشی از pipeline CI/CD هر پروژه موبایل باشد.

Strong Reference در Swift و Kotlin — مقایسه

Swift و Kotlin از مکانیزم‌های اساساً متفاوت مدیریت حافظه استفاده می‌کنند، اما مفهوم مرجع قوی در هر دو وجود دارد. در Swift از ARC با آزادسازی همزمان در retain count = 0 استفاده می‌شود. در Kotlin از GC ردیاب استفاده می‌شود که اشیاء غیرقابل دسترسی را به صورت ناهمزمان پاک می‌کند.

پارامترSwift (ARC)Kotlin (JVM GC)
مکانیزمشمارش مراجع (retain count)ردیابی دسترسی‌پذیری (GC Roots)
آزادسازیهمزمان (هنگام صفر شدن شمارنده)ناهمزمان (چرخه GC)
Retain cycleبه طور خودکار تشخیص داده نمی‌شودGC می‌تواند تشخیص دهد، اما نه فوراً
Weak refweak (صفر شدن خودکار)WeakReference (بررسی دستی)

تفاوت عملی اصلی: در Swift retain cycle — یک نشت تضمینی است. در Kotlin GC ممکن است چرخه را در صورت غیرقابل دسترسی بودن اشیاء از ریشه بشکند، اما عمر اشیاء نشتی غیرقابل پیش‌بینی باقی می‌ماند. بنابراین در هر دو زبان بهترین استراتژی — اجتناب از چرخه‌های مراجع قوی در مرحله طراحی است.

برای Swift در الگوهای delegate و بستارها از weak استفاده کنید. برای Kotlin — WeakReference یا کامپوننت‌های Lifecycle-aware که به طور خودکار مراجع را هنگام نابودی مالک پاک می‌کنند. در هر دو رویکرد هدف یکسان است — حذف مراجع قوی در جاهایی که زنجیره نگهداری ناگسستنی ایجاد می‌کنند.

سوالات متداول

تفاوت Strong Reference با Weak Reference چیست؟

Strong Reference retain count شیء را افزایش می‌دهد و تا زمانی که مرجع وجود دارد از آزادسازی آن جلوگیری می‌کند. Weak Reference retain count را تغییر نمی‌دهد و هنگامی که شیء از حافظه حذف می‌شود به طور خودکار صفر می‌شود. مراجع قوی برای مالکیت استفاده می‌شوند، مراجع ضعیف — برای اتصالات بازگشتی و delegateها.

Retain cycle چیست و چرا خطرناک است؟

Retain cycle — یک بن‌بست متقابل است که در آن دو شیء یکدیگر را با مراجع قوی نگه می‌دارند. retain count آنها هرگز به صفر نمی‌رسد، حافظه آزاد نمی‌شود. این منجر به نشت حافظه می‌شود: اشیاء برای همیشه در heap باقی می‌مانند، برنامه منابع بیشتری مصرف می‌کند و در نهایت با OutOfMemory سقوط می‌کند.

چگونه retain cycle را در برنامه iOS تشخیص دهیم؟

از Instruments Leaks از Xcode استفاده کنید — پروفایل‌گیری را با قالب Leaks شروع کنید، سناریو را در برنامه اجرا کنید و نشانگرهای نشت را بررسی کنید. برای تشخیص دقیق به برگه Cycles & Roots بروید — گراف مراجع قوی متقابل را نشان می‌دهد که یک چرخه ناگسستنی تشکیل می‌دهند.

چه زمانی باید به جای Weak از Unowned استفاده کرد؟

Unowned را زمانی استفاده کنید که عمر شیء فرزند قطعاً از عمر والد تجاوز نمی‌کند — مثلاً هنگام اتصال شیء به یک محدوده به شدت تعریف‌شده. در صورت تردید از Weak استفاده کنید، زیرا مراجعه به unowned آزاد شده باعث crash برنامه می‌شود.

آیا مراجع قوی بر عملکرد برنامه تأثیر می‌گذارند؟

به طور غیرمستقیم — بله. هر retain و release در ARC یک عملیات اتمی با سربار است. با تعداد زیاد اشیاء در چرخه‌ها، این می‌تواند بر عملکرد تأثیر بگذارد. اما مشکل اصلی — سرعت کار ARC نیست، بلکه نشت حافظه ناشی از انتخاب نادرست نوع مرجع است.

خلاصه

  • Strong Reference — مکانیزم پایه مالکیت شیء، نگه‌داشتن آن در حافظه از طریق افزایش retain count.
  • ARC مدیریت حافظه را در Swift و Objective-C خودکار می‌کند، retain و release دستی را حذف می‌کند، اما از retain cycles محافظت نمی‌کند.
  • Retain cycle با مراجع قوی متقابل ایجاد می‌شود — این علت اصلی نشت حافظه در سیستم‌های ARC است.
  • مراجع Weak و Unowned چرخه‌های مراجع قوی را بدون افزایش retain count می‌شکنند.
  • انتخاب نوع مرجع با رابطه مالکیت تعیین می‌شود: Strong برای parent→child، Weak یا Unowned برای child→parent.
  • Instruments Leaks و LeakCanary — ابزارهای اصلی تشخیص مراجع قوی مشکل‌ساز در iOS و Android.
  • گراف مالکیت را از قبل طراحی کنید — این ارزان‌تر از رفع نشت حافظه پس از انتشار برنامه است.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید