Memory Graph হল Xcode Debug Navigator-এর একটি ভিজুয়াল টুল যা অ্যাপ্লিকেশনের মেমোরিতে অবজেক্টগুলির পারস্পরিক রেফারেন্সসহ একটি গ্রাফ প্রদর্শন করে। heap dump-এর বিপরীতে, Memory Graph শুধু অবজেক্টের তালিকা নয়, বরং একটি নির্দেশিত রেফারেন্স গ্রাফ দেখায় যেখানে প্রতিটি নোড একটি অবজেক্ট এবং প্রতিটি এজ একটি রেফারেন্স (strong, weak, unowned)। Apple WWDC 2018 অনুসারে, টুলটি সেকেন্ডের মধ্যে দৃশ্যত retain cycles এবং মেমোরি লিক সনাক্ত করতে দেয়, heap dump-এর কাঁচা ডেটা বিশ্লেষণের প্রয়োজন ছাড়াই।
মূল বিষয়
Memory Graph হল Xcode Debug Navigator-এর একটি উপাদান (Xcode 10, WWDC 2018-এ প্রবর্তিত) যা ডিবাগ করা প্রক্রিয়ার মেমোরিতে থাকা সমস্ত অবজেক্টের একটি নির্দেশিত গ্রাফ তৈরি করে। গ্রাফের প্রতিটি নোড একটি ক্লাস ইনস্ট্যান্স (Objective-C বা Swift), প্রতিটি এজ অন্য অবজেক্টের একটি রেফারেন্স। এজের রঙ রেফারেন্সের ধরন নির্দেশ করে: নীল — strong, সবুজ — weak, ধূসর — unowned। গ্রাফটি LLDB এবং Objective-C runtime ডেটার ভিত্তিতে তৈরি করা হয়, তাই সঠিক কার্যক্রমের জন্য অ্যাপ্লিকেশনটিকে Debug কনফিগারেশনে সক্ষম প্রতীকসহ কম্পাইল করতে হবে।
কাজের নীতি: যখন অ্যাপ্লিকেশন breakpoint-এ থামানো হয়, Xcode LLDB-এর মাধ্যমে runtime থেকে সমস্ত জীবিত অবজেক্ট এবং তাদের রেফারেন্স অনুরোধ করে। LLDB সম্পূর্ণ গ্রাফ তৈরি করতে objc_getClassList এবং বরাদ্দ অঞ্চলের উপর পুনরাবৃত্তি ব্যবহার করে। ARM64 (Apple Silicon)-এ, ধীরগতি ছাড়াই বরাদ্দ ট্র্যাকিংয়ের জন্য অতিরিক্ত হার্ডওয়্যার উপায় ব্যবহার করা হয়। গ্রাফ নির্মাণের সময় heap আকারের উপর নির্ভর করে: একটি সাধারণ iOS অ্যাপ্লিকেশনের জন্য (50–200 MB), গ্রাফটি 1–3 সেকেন্ডে তৈরি হয়।
Apple-এর মতে, Memory Graph হল একমাত্র টুল যা কোড পরিবর্তন বা ইন্সট্রুমেন্টেশন যোগ না করেই retain cycles ভিজুয়ালাইজ করতে পারে। Instruments Leaks-এর বিপরীতে, Memory Graph Xcode-এর ভিতরে রিয়েল-টাইমে কাজ করে এবং আলাদা প্রোফাইলার চালু করার প্রয়োজন হয় না। এটি ডেভেলপমেন্টের সময় দ্রুত মেমোরি লিক ডায়াগনোসিসের জন্য প্রথম পছন্দের টুল করে তোলে।
Heap dump সংখ্যাসহ (shallow size, retained size) সমস্ত অবজেক্টের একটি টেবিল প্রদান করে — এটি পরিমাণগত বিশ্লেষণের জন্য সর্বোত্তম। Memory Graph সংযোগগুলির একটি ভিজুয়াল চিত্র প্রদান করে — চক্রীয় রেফারেন্স খোঁজার জন্য সর্বোত্তম। টুলগুলি একে অপরের পরিপূরক: প্রথমে দ্রুত retain cycle সনাক্তকরণের জন্য Memory Graph, তারপর সঠিক retained size পরিমাপের জন্য Instruments Allocations-এর মাধ্যমে heap dump। objc.io-এর মতে, উভয় পদ্ধতির সংমিশ্রণ 95% মেমোরি লিক পরিস্থিতি কভার করে।
Retain cycle এমন একটি পরিস্থিতি যখন দুই বা ততোধিক অবজেক্ট একে অপরকে strong রেফারেন্স দিয়ে ধরে রাখে, একটি বন্ধ লুপ তৈরি করে। ARC এই ধরনের লুপ ডিলোকেট করতে পারে না কারণ প্রতিটি অবজেক্টের retain count কখনই শূন্যে পৌঁছায় না। একটি ক্লাসিক উদাহরণ: ViewController এবং View, যেখানে View-এর একটি closure-এর strong রেফারেন্স রয়েছে যা self (ViewController) ক্যাপচার করে। Memory Graph এই ধরনের লুপকে রিং (চক্র) হিসাবে প্রদর্শন করে, দ্রুত সনাক্তকরণের জন্য সেগুলো হাইলাইট করে।
যখন Xcode একটি retain cycle সনাক্ত করে, এটি কমলা রূপরেখা দিয়ে হাইলাইট করে এবং Debug Navigator-এ একটি সতর্কতা দেখায়। চক্রটিতে ক্লিক করলে বন্ধ লুপ গঠনকারী রেফারেন্সের চেইন দেখা যায়। ডেভেলপারকে কেবল নির্ধারণ করতে হবে কোন strong এজটি weak হওয়া উচিত — সাধারণত এটি চাইল্ড অবজেক্ট থেকে প্যারেন্টের একটি রেফারেন্স (যেমন delegate বা closure)।
class ViewController: UIViewController {
let service = DataService()
override func viewDidLoad() {
super.viewDidLoad()
// ❌ Retain cycle: ViewController → service → closure → ViewController
service.fetchData { self.updateUI($0) }
}
func updateUI(_ data: Data) {}
}
class DataService {
var completion: ((Data) -> Void)?
func fetchData(handler: @escaping (Data) -> Void) {
self.completion = handler
}
}
Memory Graph-এ আপনি একটি ত্রিভুজ দেখতে পাবেন: ViewController → DataService → closure → ViewController। সমাধান হল self-এর ক্যাপচার দুর্বল করা: [weak self]। সংশোধনের পর, Memory Graph closure থেকে ViewController-এ একটি সবুজ এজ দেখাবে, এবং retain cycle অদৃশ্য হয়ে যাবে।
// সংশোধিত কোড — self-এর দুর্বল ক্যাপচার
service.fetchData { [weak self] data in
guard let self else { return }
self.updateUI(data)
}
Memory Graph Debugger-এর ইন্টারফেস তিনটি প্যানেল নিয়ে গঠিত: বাম — ইনস্ট্যান্স গণনাসহ সমস্ত জীবিত অবজেক্টের তালিকা (ক্লাস অনুযায়ী গ্রুপকৃত); মাঝখানে — টেনে আনা যায় এমন নোডসহ একটি ভিজুয়াল গ্রাফ; ডান — নির্বাচিত অবজেক্ট বা এজের জন্য একটি ইন্সপেক্টর। অবজেক্ট তালিকা প্রদর্শন করে: ক্লাস আইকন, মেমোরিতে ইনস্ট্যান্সের সংখ্যা, মোট retained size এবং সম্পূর্ণ heap-এর শতাংশ। ক্লাসের নাম অনুসারে ফিল্টারিং রেগুলার এক্সপ্রেশন সমর্থন করে।
গ্রাফের নোডগুলি পড়ার সুবিধার্থে টেনে সরানো যায়। একটি নোডে ডাবল-ক্লিক করলে অবজেক্ট সম্পর্কে বিস্তারিত তথ্য খোলে: টাইপ এবং মানসহ এর সমস্ত বৈশিষ্ট্য, প্রতিটি বৈশিষ্ট্যের জন্য কল স্ট্যাক (backtrace), এবং retain/release ইতিহাস। Backtrace একটি মূল বৈশিষ্ট্য: এটি দেখায় কোডের কোন সঠিক লাইনটি অবজেক্টের রেফারেন্স স্থাপন করেছে। এটি ম্যানুয়ালি সমস্ত কোড পর্যালোচনা না করেই লিকের উৎস খুঁজে পেতে দেয়।
জটিল গ্রাফের জন্য, Xcode Layout → Hierarchical বা Cluster-এর মাধ্যমে স্বয়ংক্রিয় লেআউট প্রদান করে। পদানুক্রমিক লেআউট রুট অবজেক্টগুলোকে উপরে এবং চাইল্ডগুলোকে নীচে রাখে, চেইন খোঁজা সহজ করে। ক্লাস্টার গ্রুপিং সম্পর্কিত অবজেক্টগুলোকে ক্লাস্টারে গ্রুপ করে, যা সুবিধাজনক যখন গ্রাফে বেশ কয়েকটি বিচ্ছিন্ন গ্রুপ থাকে। Apple-এর মতে, বেশিরভাগ অ্যাপ্লিকেশনের জন্য পদানুক্রমিক লেআউট সুপারিশ করা হয় — এটি স্বজ্ঞাত এবং ভিজুয়াল বিশ্লেষণে কম সময় নেয়।
// LLDB কমাঠ8ড যা Memory Graph আন্তরিকভাবে ব্যবহার করে
(lldb) script import lldb.macosx.heap
(lldb) script heap.find_variable("viewController")
0x600000c4b80: ViewController
(lldb) script heap.refs 0x600000c4b80
0x600000c4b80 -> 0x600003a4c00 (DataService)
ivar: _service, offset: 16
Memory Graph বিশ্লেষণের জন্য একটি পদ্ধতিগত পদ্ধতিতে বেশ কয়েকটি ধাপ অন্তর্ভুক্ত। ধাপ 1: অ্যাপ্লিকেশন চালান, এমন একটি পরিস্থিতি সম্পাদন করুন যা সম্ভাব্যভাবে লিক সৃষ্টি করে (স্ক্রিন খুলুন/বন্ধ করুন, নেটওয়ার্ক অনুরোধ করুন)। ধাপ 2: Debug Navigator-এ Memory Graph বাটনে ক্লিক করুন — Xcode গ্রাফ তৈরি করে। ধাপ 3: বাম প্যানেলে কমলা retain cycle সতর্কতাগুলি পরীক্ষা করুন। ধাপ 4: সন্দেহজনক অবজেক্টের জন্য, Show only cycles বিকল্পটি ব্যবহার করুন — শুধুমাত্র চক্রীয় রেফারেন্সে জড়িত নোডগুলি প্রদর্শিত হবে।
একবার retain cycle পাওয়া গেলে, চক্রের এজে ক্লিক করুন এবং ইন্সপেক্টর প্যানেল খুলুন। Backtrace বিভাগটি সেই মুহূর্তে কল স্ট্যাক দেখায় যখন এই রেফারেন্সটি স্থাপন করা হয়েছিল। উদাহরণস্বরূপ, যদি এজটি closure থেকে self-এর দিকে যায়, backtrace দেখাবে কোন পদ্ধতিতে এবং কোডের কোন লাইনে closure তৈরি করা হয়েছিল। এটি অনুমানের প্রয়োজন দূর করে — আপনি সঙ্গে সঙ্গেই বিন্দুটি দেখতে পান যেখানে সমস্যাযুক্ত রেফারেন্স তৈরি হয়েছিল। WWDC Labs-এর মতে, backtrace বিশ্লেষণ retain cycle নির্ণয়ের সময় 15–20 মিনিট থেকে 2–3 মিনিটে কমিয়ে দেয়।
class ProfileViewController: UIViewController {
var profileView: ProfileView!
override func viewDidLoad() {
super.viewDidLoad()
profileView = ProfileView()
// Memory Graph এখানে retain cycle দেখাবে
profileView.onTap = { [unowned self] in
// ⚠️ unowned self nil হলে crash ঘটাতে পারে
self.navigateToDetail()
}
}
func navigateToDetail() { }
}
// ✅ ঠিক: [weak self] + guard let self
profileView.onTap = { [weak self] in
guard let self else { return }
self.navigateToDetail()
}
Memory Graph হাজার হাজার অবজেক্ট প্রদর্শন করতে পারে, যা খোঁজা কঠিন করে তোলে। বাম প্যানেলে ফিল্টার ব্যবহার করুন: একটি ক্লাসের নাম লিখুন (যেমন ProfileViewController) শুধুমাত্র সেই ক্লাসের ইনস্ট্যান্স প্রদর্শন করতে। তারপর একটি ইনস্ট্যান্স নির্বাচন করুন যা ডিলোকেট হওয়া উচিত ছিল (যদি স্ক্রিন বন্ধ থাকে কিন্তু অবজেক্ট থেকে যায়)। Show Reachable From প্রয়োগ করুন — শুধুমাত্র এই অবজেক্টের জন্য প্রাসঙ্গিক রেফারেন্সগুলি প্রদর্শিত হবে, বাকি গ্রাফ লুকানো থাকবে।
অভিজ্ঞ ডেভেলপাররা Memory Graph শুধু লিক খোঁজার জন্যই নয়, সক্রিয় মেমোরি নিয়ন্ত্রণের জন্যও ব্যবহার করেন। প্রতিটি বড় আর্কিটেকচার পরিবর্তনের পর Memory Graph পরীক্ষা করুন — নতুন delegate, closure বা NotificationCenter সাবস্ক্রিপশন যোগ করা। শুধু একটি সাধারণ পরিস্থিতি চালান এবং নিশ্চিত করুন যে অবজেক্টগুলি সঠিকভাবে ডিলোকেট হচ্ছে এবং retain cycles অনুপস্থিত। এটি 2–3 মিনিট সময় নেয় কিন্তু পরবর্তী ঘন্টার ডিবাগিং প্রতিরোধ করে।
Xcode-এ Memory Report (Debug Navigator ট্যাব) রিয়েল-টাইমে মেমোরি ব্যবহারের একটি গ্রাফ দেখায়। এটি Memory Graph-এর সাথে ব্যবহার করুন: তীব্র ব্যবহার বৃদ্ধিতে Memory Graph খুলুন। উদাহরণস্বরূপ, ছবি লোড করা সেলসহ দীর্ঘ তালিকা স্ক্রোল করার সময়, Memory Graph দেখাবে কোন অবজেক্ট তৈরি হচ্ছে এবং কোনটি ডিলোকেট হচ্ছে। যদি অবজেক্টের সংখ্যা হ্রাস না পেয়ে বাড়ে — এটি একটি সম্ভাব্য লিক যা ক্র্যাশ হওয়ার আগেই দৃশ্যমান। Apple-এর মতে, Memory Graph + Memory Report-এর সংমিশ্রণ হল Xcode 12 থেকে সমস্ত iOS ডেভেলপারদের জন্য প্রস্তাবিত ওয়ার্কফ্লো।
// Objective-C-এ delegation-এর মাধ্যমে লিকের উদাহরণ
@interface DownloadManager : NSObject
@property (strong) id delegate; // ❌ weak হতে হবে!
@end
@implementation DownloadManager
// Memory Graph retain cycle দেখাবে:
// ViewController → DownloadManager.delegate → ViewController
@end
// সমাধান: weak property
@property (weak) id delegate;
বিশেষ মনোযোগ দিন closures-এ — Swift-এ retain cycles-এর সবচেয়ে সাধারণ উৎস। একটি অবজেক্টের বৈশিষ্ট্য হিসাবে সংরক্ষিত closure-এর ভিতরে self ক্যাপচার করলে একটি ক্লাসিক চক্র তৈরি হয়। Memory Graph এটি একটি closure ({} প্রতীকসহ নোড) হিসাবে প্রদর্শন করে যা ক্যাপচার করা অবজেক্টের সাথে নীল এজ দ্বারা সংযুক্ত। নিয়মিত সমস্ত closures পরীক্ষা করুন, বিশেষ করে যেগুলো অ্যাসিঙ্ক্রোনাস কল, GCD, Combine এবং SwiftUI-তে ব্যবহৃত হয়। Point-Free পরিসংখ্যান অনুসারে, Swift প্রকল্পে 90% লিক self ক্যাপচার করা closures-এর সাথে সম্পর্কিত।
সচরাচর জিজ্ঞাসিত প্রশ্ন
Memory Graph উভয় ভাষার জন্যই কাজ করে কারণ এটি Objective-C runtime ব্যবহার করে। ObjC-এর সাথে সামঞ্জস্যপূর্ণ Swift অবজেক্ট (@objc দিয়ে চিহ্নিত NSObject উপশ্রেণী) সম্পূর্ণরূপে প্রদর্শিত হয়। ObjC ব্রিজিং ছাড়া বিশুদ্ধ Swift স্ট্রাকচার এবং ক্লাস সীমিতভাবে দেখা যায়।
অবজেক্টগুলিকে Objective-C runtime-এ নিবন্ধিত হতে হবে। Swift value types (struct, enum) প্রদর্শিত হয় না। নিশ্চিত করুন যে ক্লাস NSObject থেকে উত্তরাধিকার সূত্রে প্রাপ্ত বা Memory Graph-এ দৃশ্যমানতার জন্য @objc বৈশিষ্ট্য ব্যবহার করে।
নীল — strong রেফারেন্স, অবজেক্ট ধরে রাখে। সবুজ — weak রেফারেন্স, জীবনচক্রকে প্রভাবিত করে না। ধূসর — unowned রেফারেন্স। Retain cycle শুধুমাত্র নীল এজ থেকে তৈরি হয়।
গ্রাফ তৈরি অ্যাপ্লিকেশনকে 1–3 সেকেন্ডের জন্য বিরাম দেয় এবং অস্থায়ীভাবে Xcode মেমোরি খরচ 200–500 MB বাড়াতে পারে। অ্যাপ্লিকেশন নিজেই ধীর হয় না কারণ পরিদর্শন breakpoint বিরতির সময় ঘটে।
Xcode সরাসরি গ্রাফ রপ্তানি সমর্থন করে না। ডকুমেন্টেশনের জন্য স্ক্রিনশট বা প্রোগ্রাম্যাটিক ডেটা নিষ্কাশনের জন্য lldb স্ক্রিপ্ট heap.find_variable ব্যবহার করুন। বিস্তারিত বিশ্লেষণের জন্য, heap dump-সহ Instruments Allocations ব্যবহার করুন।
সারসংক্ষেপ
{} নোড হিসাবে প্রদর্শন করে।আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন