Automatic Reference Counting (ARC) Swift और Objective-C में एक मेमोरी प्रबंधन प्रणाली है जो स्वचालित रूप से प्रत्येक ऑब्जेक्ट के संदर्भों की संख्या गिनती है और काउंटर के शून्य होने पर उसे मुक्त कर देती है। Apple Swift दस्तावेज़ीकरण, 2026 के अनुसार, ARC कंपाइलर में एम्बेडेड है और कंपाइलेशन चरण में काम करता है, सही स्थानों पर retain/release कॉल डालता है। Garbage Collection के विपरीत, ARC को किसी अलग कलेक्टर थ्रेड की आवश्यकता नहीं है और एप्लिकेशन निष्पादन के दौरान कोई ठहराव पैदा नहीं करता।
मुख्य बिंदु
ARC (Automatic Reference Counting) एक कंपाइलर-आधारित मेमोरी प्रबंधन तंत्र है जिसे Apple ने Xcode 4.2 (2011) में Objective-C के लिए पेश किया और Swift ने इसे विरासत में लिया। मैन्युअल मेमोरी प्रबंधन (Manual Retain-Release, MRR) के विपरीत, ARC retain, release और autorelease कॉल को पूरी तरह से स्वचालित करता है, उन्हें डेवलपर के हस्तक्षेप के बिना कंपाइलेशन चरण में डालता है।
ARC कोई कचरा संग्राहक नहीं है। यह गतिशील कोड सम्मिलन के साथ स्थिर विश्लेषण है: कंपाइलर ऑब्जेक्ट जीवनकाल का विश्लेषण करता है और उन बिंदुओं पर retain/release रखता है जहाँ ऑब्जेक्ट बनाए, कॉपी या दायरे से बाहर जाते हैं। परिणाम नियतात्मक मेमोरी मुक्ति है: ऑब्जेक्ट ठीक उसी समय हटा दिया जाता है जब उस पर कोई और संदर्भ नहीं रहता, बिना देरी या ठहराव के।
WWDC 2011 Session 323 के अनुसार, MRR से ARC में स्विच करने ने Apple एप्लिकेशन में मेमोरी-संबंधित क्रैश बग को 70% तक कम कर दिया। डेवलपर्स ने मैन्युअल रूप से retain/release संतुलित करना बंद कर दिया, जिससे लीक और double-free त्रुटियों की एक पूरी श्रेणी समाप्त हो गई।
मेमोरी में प्रत्येक ऑब्जेक्ट का एक संदर्भ काउंटर (retain count) होता है। जब कोई ऑब्जेक्ट बनाया जाता है, तो काउंटर 1 पर सेट होता है। जब कोई नया strong संदर्भ ऑब्जेक्ट की ओर इशारा करता है — काउंटर बढ़ता है (retain)। जब strong संदर्भ गायब हो जाता है — काउंटर घटता है (release)। शून्य तक पहुँचने पर, ऑब्जेक्ट तुरंत मुक्त हो जाता है।
Swift कंपाइलर हर असाइनमेंट पर retain/release नहीं डालता — वह अनुकूलन के लिए स्थिर विश्लेषण का उपयोग करता है। उदाहरण के लिए, यदि कोई ऑब्जेक्ट पास होने के बाद उपयोग नहीं होने की गारंटी है, तो कंपाइलर अनावश्यक release/retain छोड़ सकता है। इस अनुकूलन को ARC Optimization कहा जाता है।
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) initialized (retain count: 1)")
}
deinit {
print("\(name) deallocated")
}
}
func testARC() {
let p = Person(name: "Alice") // retain count = 1
let q = p // retain count = 2
// q दायरे से बाहर जाता है
// retain count = 1
// p दायरे से बाहर जाता है
// retain count = 0 → deinit
}
यह उदाहरण दिखाता है कि ARC काउंटर को कैसे प्रबंधित करता है: q = p असाइन करने पर काउंटर बढ़ता है; q के दायरे से बाहर जाने पर घटता है। जब अंतिम strong संदर्भ गायब हो जाता है, तो डीइनिशियलाइज़र तुरंत कॉल किया जाता है। कोई कचरा संग्राहक इंतज़ार नहीं करता — मेमोरी तुरंत मुक्त हो जाती है।
ARC और Garbage Collection एक ही समस्या — स्वचालित मेमोरी प्रबंधन — को हल करते हैं लेकिन मौलिक रूप से भिन्न दृष्टिकोणों के साथ। उनके बीच का चुनाव भाषा की वास्तुकला को परिभाषित करता है: Swift (ARC) बनाम Java/Go (GC)। आइए मुख्य अंतरों पर नज़र डालें।
| विशेषता | ARC (Swift/ObjC) | GC (Java/Go) |
|---|---|---|
| मुक्ति का समय | नियतात्मक: काउंटर के शून्य होने पर तुरंत | अनियतात्मक: अगले संग्रह चक्र पर |
| निष्पादन ठहराव | कोई नहीं (retain/release कंपाइलेशन पर डाले गए) | Stop-The-World ठहराव (2–200 मि.से.) |
| ओवरहेड | प्रत्येक संदर्भ पर काउंटर वृद्धि/कमी | ऑब्जेक्ट ग्राफ़ ट्रैवर्सल, मार्किंग, स्वीपिंग |
| समस्याएँ | Retain Cycle (मैन्युअल समाधान) | हीप विखंडन, भूले हुए संदर्भों से लीक |
| अतिरिक्त थ्रेड | आवश्यक नहीं | कचरा संग्राहक थ्रेड आवश्यक |
मुख्य समझौता: ARC पूर्वानुमानित ऑब्जेक्ट जीवनकाल और शून्य ठहराव प्रदान करता है, लेकिन डेवलपर को retain cycles को समझने और weak/unowned को सही ढंग से चुनने की आवश्यकता होती है। GC डेवलपर को इन चिंताओं से मुक्त करता है, लेकिन अनियतात्मक ठहराव और एक अतिरिक्त थ्रेड की कीमत पर।
ARC तीन प्रकार के संदर्भ क्वालिफ़ायर को परिभाषित करता है, प्रत्येक काउंटर और ऑब्जेक्ट जीवनचक्र को अलग तरह से प्रभावित करता है। सही क्वालिफ़ायर चुनना Swift में सुरक्षित मेमोरी प्रबंधन की नींव है।
Strong डिफ़ॉल्ट क्वालिफ़ायर है। प्रत्येक strong संदर्भ ऑब्जेक्ट के retain count को 1 बढ़ाता है। जब तक कम से कम एक strong संदर्भ मौजूद है, ऑब्जेक्ट जीवित रहता है। Swift में सभी क्लास गुण और स्थानीय चर डिफ़ॉल्ट रूप से strong हैं। Strong संदर्भ एक स्वामित्व संबंध बनाते हैं: ऑब्जेक्ट A, ऑब्जेक्ट B का मालिक है।
Weak एक संदर्भ है जो retain count नहीं बढ़ाता। एक ऑब्जेक्ट मुक्त किया जा सकता है भले ही उस पर weak संदर्भ इशारा कर रहा हो। मुक्ति के बाद, weak संदर्भ स्वचालित रूप से nil पर सेट हो जाता है। Weak संदर्भ हमेशा var के रूप में वैकल्पिक प्रकार (?) के साथ घोषित किए जाते हैं। इनका उपयोग retain cycles को तोड़ने के लिए किया जाता है, विशेष रूप से delegate पैटर्न में।
Unowned एक गैर-स्वामित्व संदर्भ है, जो weak की तरह retain count नहीं बढ़ाता। हालांकि, मुक्ति के बाद unowned संदर्भ nil पर सेट नहीं होता — मुक्त ऑब्जेक्ट तक पहुँच क्रैश का कारण बनती है। Unowned का उपयोग तब किया जाता है जब यह गारंटी हो कि ऑब्जेक्ट कम से कम संदर्भित करने वाले ऑब्जेक्ट जितना जीवित रहता है। विशिष्ट उपयोग मामले क्लोज़र (closures) और गारंटीकृत जीवनकाल वाले माता-पिता-बच्चे संबंध हैं।
class Customer {
let name: String
var card: CreditCard? // strong
init(name: String) { self.name = name }
deinit { print("\(name) deallocated") }
}
class CreditCard {
let number: String
unowned let customer: Customer // unowned — मालिक नहीं
init(number: String, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card \(number) deallocated") }
}
var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer और CreditCard दोनों मुक्त — कोई retain cycle नहीं
यहाँ CreditCard Customer के लिए unowned संदर्भ का उपयोग करता है। Customer कार्ड का मालिक है (strong), और कार्ड ग्राहक का मालिक नहीं है (unowned)। जब Customer मुक्त होता है, दोनों ऑब्जेक्ट मुक्त हो जाते हैं — कोई retain cycle नहीं होता। यदि card.customer strong होता, तो चक्र मुक्ति को अवरुद्ध कर देता।
स्वचालन के बावजूद, ARC कोई जादू की छड़ी नहीं है। डेवलपर्स कई विशिष्ट समस्याओं का सामना करते हैं जिनके लिए आंतरिक मेमोरी प्रबंधन तंत्र की समझ की आवश्यकता होती है।
Swift में क्लोज़र (closures) बाहरी चर को strong संदर्भ द्वारा कैप्चर करते हैं। यदि कोई क्लोज़र किसी क्लास गुण को असाइन किया गया है और self को कैप्चर करता है — एक retain cycle उत्पन्न होता है: क्लास क्लोज़र को रखता है, क्लोज़र self को रखता है। समाधान weak या unowned के साथ कैप्चर सूची है।
class NetworkManager {
var completionHandler: ((Data?) -> Void)?
var data: Data?
func fetchData() {
completionHandler = { [weak self] result in
guard let self else { return }
self.data = result
self.processResult()
}
}
func processResult() { }
}
कैप्चर सूची [weak self] क्लोज़र के अंदर self के लिए weak संदर्भ बनाती है। यह संभावित retain cycle को तोड़ती है। Guard let self कोड निष्पादित करने से पहले ऑब्जेक्ट के जीवित होने की गारंटी देता है। Swift में एसिंक्रोनस क्लोज़र के लिए weak self मानक अभ्यास है।
हालाँकि retain/release हल्के संचालन हैं, गर्म लूप में बार-बार काउंटर वृद्धि/कमी ओवरहेड जोड़ती है। Swift 5.9+ में, कंपाइलर अनुकूलन का उपयोग करता है जो अनावश्यक retain/release को हटा देता है यदि विश्लेषक इसे सुरक्षित साबित करता है। हालांकि, Objective-C में, retain/release अभी भी प्रति सेकंड लाखों कॉल वाले उच्च-भार परिदृश्यों में बाधा बन सकते हैं।
Autorelease Pool एक विलंबित रिलीज़ तंत्र है जिसका उपयोग Objective-C और कुछ Swift परिदृश्यों में किया जाता है। ऑब्जेक्ट को पूल में रखा जाता है और पूल के खाली होने पर release प्राप्त होता है। कई अस्थायी ऑब्जेक्ट (जैसे JSON पार्सिंग) वाले लूप में, कस्टम autoreleasepool बनाने से शिखर मेमोरी खपत कम होती है।
अक्सर पूछे जाने वाले प्रश्न
मैन्युअल प्रबंधन (MRR) में, डेवलपर स्पष्ट रूप से retain, release और autorelease को कॉल करता था। ARC इन कॉल को कंपाइलेशन चरण में स्वचालित रूप से डालता है, double-free के जोखिम, भूले हुए release से लीक और retain/release संतुलन त्रुटियों को समाप्त करता है।
ARC केवल Objective-C ऑब्जेक्ट और Swift क्लास का प्रबंधन करता है। C/C++ संरचनाओं और पॉइंटर्स के लिए, ARC लागू नहीं होता — इन ऑब्जेक्ट को मैन्युअल रूप से या C++ स्मार्ट पॉइंटर्स (shared_ptr, unique_ptr) के माध्यम से प्रबंधित किया जाता है। Core Foundation ऑब्जेक्ट (CFString, CGColor) भी ARC के अंतर्गत नहीं आते।
weak — जब ऑब्जेक्ट संदर्भित करने वाले ऑब्जेक्ट से पहले मुक्त हो सकता है (डेलीगेट, एसिंक्रोनस क्लोज़र)। unowned — जब यह गारंटी हो कि ऑब्जेक्ट कम से कम संदर्भित करने वाले जितना जीवित रहता है (माता-पिता-बच्चे जहाँ बच्चा माता-पिता के बिना मौजूद नहीं हो सकता)। यदि निश्चित नहीं हैं, तो weak चुनें।
Swift में एक्ज़िस्टेंशियल प्रकार (protocol as type) मान को एक विशेष कंटेनर (existential container) में लपेटते हैं। यह प्रोटोकॉल सीमाओं पर retain/release की संख्या बढ़ाता है। Swift 5.7+ में, अपारदर्शी परिणाम प्रकार (opaque result types) और some पैरामीटर कंटेनर को हटाकर ओवरहेड कम करते हैं।
Swift में retain count पढ़ने के लिए कोई सीधा API नहीं है — इसे कार्यान्वयन विवरण माना जाता है। निदान के लिए, Xcode में Instruments (Allocations, Leaks) या Memory Debugger का उपयोग करें। ये उपकरण जीवित क्लास इंस्टेंस की संख्या और धारण श्रृंखलाएँ दिखाते हैं।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें