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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন