Memory Graph — tətbiqin operativ yaddaşındakı obyektlərin qarşılıqlı istinadları ilə qrafını göstərən Xcode Debug Navigator-un vizual alətidir. Heap dump-dan fərqli olaraq, Memory Graph sadəcə obyekt siyahısını deyil, hər bir düyünün obyekt və hər bir kənarın istinad (strong, weak, unowned) olduğu istiqamətlənmiş istinad qrafını göstərir. Apple WWDC 2018-ə əsasən, alət saniyələr ərzində retain cycles və yaddaş sızmalarını vizual olaraq aşkar etməyə imkan verir, xam yığın dump məlumatlarını təhlil etmək tələb olunmur.
Əsas məqamlar
Memory Graph — Xcode Debug Navigator komponentidir (Xcode 10, WWDC 2018-də ortaya çıxıb), debug edilən prosesin yaddaşındakı bütün obyektlərin istiqamətlənmiş qrafını qurur. Qrafın hər bir düyünü sinif nümunəsidir (Objective-C və ya Swift), hər bir kənar digər obyektə istinaddır. Kənarın rəngi istinad növünü göstərir: mavi — strong, yaşıl — weak, boz — unowned. Qraf LLDB və Objective-C runtime məlumatları əsasında qurulur, buna görə düzgün işləməsi üçün tətbiq Debug konfiqurasiyasında simvollar açıq vəziyyətdə yığılmalıdır.
İş prinsipi: tətbiq breakpoint-də dayandırıldıqda, Xcode LLDB vasitəsilə runtime-dan bütün canlı obyektləri və onların istinadlarını sorğulayır. LLDB tam qraf qurmaq üçün objc_getClassList və ayırma regionları üzrə iterasiyadan istifadə edir. ARM64-də (Apple Silicon) yavaşlatma olmadan ayırmanın izlənməsi üçün əlavə aparat vasitələrindən istifadə olunur. Qrafın qurulma müddəti yığın ölçüsündən asılıdır: tipik iOS tətbiqi (50–200 MB) üçün qraf 1–3 saniyəyə qurulur.
Apple-ın məlumatına görə, Memory Graph kodu dəyişdirmədən və ya instrumentasiya əlavə etmədən retain cycles-i vizuallaşdıra bilən yeganə alətdir. Instruments Leaks-dən fərqli olaraq, Memory Graph Xcode daxilində real vaxtda işləyir və profilçinin ayrıca işə salınmasını tələb etmir. Bu, onu inkişaf prosesində yaddaş sızmalarının sürətli diaqnostikası üçün ilk seçim aləti edir.
Heap dump rəqəmlərlə (shallow size, retained size) bütün obyektlərin cədvəlini verir — kəmiyyət təhlili üçün optimaldır. Memory Graph əlaqələrin vizual mənzərəsini verir — siklik istinadların axtarışı üçün optimaldır. Alətlər bir-birini tamamlayır: əvvəlcə Memory Graph sürətli retain cycles aşkarlanması üçün, sonra Instruments Allocations vasitəsilə heap dump dəqiq retained size ölçülməsi üçün. objc.io-nun təcrübəsinə görə, iki metodun kombinasiyası yaddaş sızması ssenarilərinin 95%-ni əhatə edir.
Retain cycle — iki və ya daha çox obyektin bir-birini güclü istinadlarla saxlayaraq qapalı kontur yaratdığı vəziyyətdir. ARC belə konturu sərbəst buraxa bilməz, çünki hər bir obyektin retain count-u heç vaxt sıfıra çatmır. Klassik nümunə: ViewController və View, burada View-in closure-a strong reference-i var və closure self-i (ViewController) tutur. Memory Graph belə konturları üzük (dövr) şəklində göstərir, sürətli identifikasiya üçün onları vurğulayır.
Xcode retain cycle aşkar etdikdə, onu narıncı konturla vurğulayır və Debug Navigator-da xəbərdarlıq göstərir. Dövrə kliklədikdə, qapalı kontur yaradan istinad zəncirini görürsünüz. Tərtibatçıya hansı güclü kənarın zəif olmalı olduğunu müəyyən etmək qalır — adətən bu, uşaq obyektdən valideynə olan istinaddır (məsələn, delegate və ya closure).
class ViewController: UIViewController {
let service = DataService()
override func viewDidLoad() {
super.viewDidLoad()
// ❌ Retain dövrü: ViewController → xidmət → 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-da üçbucaq görəcəksiniz: ViewController → DataService → closure → ViewController. Həll yolu — self-in zəif tutulması: [weak self]. Düzəlişdən sonra Memory Graph closure-dən ViewController-a yaşıl kənar göstərəcək və retain cycle yox olacaq.
// Düzəldilmiş kod — self-in zəif tutulması
service.fetchData { [weak self] data in
guard let self else { return }
self.updateUI(data)
}
Memory Graph Debugger interfeysi üç paneldən ibarətdir: sol — bütün canlı obyektlərin (siniflərə qruplaşdırılmış) siyahısı nümunə sayı ilə; mərkəz — sürüklənə bilən düyünləri olan vizual qraf; sağ — seçilmiş obyektin və ya kənarın inspektoru. Obyekt siyahısında göstərilir: sinif ikonu, yaddaşdakı nümunə sayı, ümumi retained size və bütün yığına nisbətən faiz. Sinif adı üzrə filtrləmə müntəzəm ifadələri dəstəkləyir.
Qraf düyünləri oxunaqlılığı yaxşılaşdırmaq üçün sürüklənə bilər. Düyünün üzərinə iki dəfə klikləmək obyekt haqqında ətraflı məlumat açır: tipləri və dəyərləri ilə bütün xassələri, hər bir xassə üçün çağırış yığını (backtrace) və retain/release tarixçəsi. Backtrace — əsas funksiyadır: obyektə istinadı hansı kod sətirinin qurduğunu göstərir. Bu, bütün kodu əl ilə nəzərdən keçirmədən sızma mənbəyini tapmağa imkan verir.
Mürəkkəb qraflar üçün Xcode Layout → Hierarchical (ierarxik) və ya Cluster (klaster) vasitəsilə avtomatik düzülüş təmin edir. İerarxik düzülüş kök obyektləri yuxarıda, uşaq obyektləri aşağıda yerləşdirir, zəncirlərin axtarışını asanlaşdırır. Klaster düzülüşü əlaqəli obyektləri qruplaşdırır, bu qraf bir neçə təcrid olunmuş qrup ehtiva etdikdə əlverişlidir. Apple-ın məlumatına görə, əksər tətbiqlər üçün ierarxik düzülüş tövsiyə olunur — intuitivdir və vizual analizə daha az vaxt aparır.
// Memory Graph tərəfindən istifadə olunan LLDB əmrləri
(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 analizinə sistematik yanaşma bir neçə mərhələni əhatə edir. Mərhələ 1: tətbiqi işə salın, potensial sızmaya səbəb olan ssenarini yerinə yetirin (ekranı açın/bağlayın, şəbəkə sorğusu edin). Mərhələ 2: Debug Navigator-da Memory Graph düyməsini basın — Xcode qraf quracaq. Mərhələ 3: sol paneldə narıncı retain cycles xəbərdarlıqlarını yoxlayın. Mərhələ 4: şübhəli obyektlər üçün Show only cycles seçimindən istifadə edin — yalnız siklik istinadlara daxil olan düyünlər göstəriləcək.
Retain cycle tapıldıqda, dövr kənarına klikləyin və inspektor panelini açın. Backtrace bölməsində bu istinadın qurulduğu andakı çağırış yığını göstərilir. Məsələn, kənar closure-dən self-ə aparırsa, backtrace closure-in hansı metoddə və hansı kod sətirində yaradıldığını göstərəcək. Bu, təxmin etmək ehtiyacını aradan qaldırır — problemli istinadın yaradılma nöqtəsini dərhal görürsünüz. WWDC Labs-ın məlumatına görə, backtrace analizi retain cycle diaqnostikası müddətini 15–20 dəqiqədən 2–3 dəqiqəyə qədər azaldır.
class ProfileViewController: UIViewController {
var profileView: ProfileView!
override func viewDidLoad() {
super.viewDidLoad()
profileView = ProfileView()
// Memory Graph retain dövrünü burada göstərəcək
profileView.onTap = { [unowned self] in
// ⚠️ unowned nil self-də crash-a səbəb ola bilər
self.navigateToDetail()
}
}
func navigateToDetail() { }
}
// ✅ Düzgün: [weak self] + guard let self
profileView.onTap = { [weak self] in
guard let self else { return }
self.navigateToDetail()
}
Memory Graph minlərlə obyekt göstərə bilər, axtarışı çətinləşdirir. Sol paneldə filtrlərdən istifadə edin: sinif adını daxil edin (məsələn, ProfileViewController), yalnız bu sinfin nümunələrini göstərmək üçün. Sonra sərbəst buraxılmalı olan nümunəni seçin (ekran bağlıdırsa, lakin obyekt qalıbsa). Show Reachable From tətbiq edin — yalnız bu obyekt üçün əhəmiyyətli olan istinadlar göstəriləcək, qrafın qalan hissəsi gizlənəcək.
Təcrübəli tərtibatçılar Memory Graph-dən təkcə sızmaların axtarışı üçün deyil, həm də proaktiv yaddaş nəzarəti üçün istifadə edirlər. Memory Graph-i yoxlayın hər bir böyük arxitektura dəyişikliyindən sonra — yeni delegate, closure və ya NotificationCenter abunəsi əlavə etdikdə. Tipik ssenarini yerinə yetirmək və obyektlərin düzgün sərbəst buraxıldığına, retain cycles-in olmadığına əmin olmaq kifayətdir. Bu 2–3 dəqiqə çəkir, lakin sonrakı saatlarla debug etmənin qarşısını alır.
Memory Report Xcode-da (Debug Navigator vərəqəsi) real vaxtda yaddaş istehlakı qrafikini göstərir. Memory Graph ilə birlikdə istifadə edin: yaddaş istehlakı kəskin artdıqda Memory Graph-i açın. Məsələn, şəkillər yükləyən hüceyrələrlə uzun siyahını sürüşdürərkən, Memory Graph hansı obyektlərin yaradıldığını və hansının sərbəst buraxıldığını göstərəcək. Obyektlərin sayı azalmadan artırsa — bu potensial sızmadır, crash-a səbəb olmadan əvvəl görünür. Apple-ın məlumatına görə, Memory Graph + Memory Report kombinasiyası Xcode 12-dən başlayaraq bütün iOS tərtibatçıları üçün tövsiyə olunan iş axınıdır.
// Objective-C-də delegasiya vasitəsilə sızma nümunəsi
@interface DownloadManager : NSObject
@property (strong) id delegate; // ❌ Weak olmalıdır!
@end
@implementation DownloadManager
// Memory Graph retain dövrünü göstərəcək:
// ViewController → DownloadManager.delegate → ViewController
@end
// Düzəliş: weak property
@property (weak) id delegate;
Xüsusi diqqət closures-a yetirin — Swift-də retain cycles-in ən çox yayılmış mənbəyi. Obyektin xassəsi kimi saxlanılan closure daxilində self tutulduqda klassik dövr yaranır. Memory Graph bunu closure ( {} simvolu ilə düyün) kimi göstərir, tutulan obyektlərlə mavi kənarlarla birləşdirilir. Bütün closures-ları mütəmadi yoxlayın, xüsusən də asinxron çağırışlarda, GCD, Combine və SwiftUI-də istifadə olunanları. Point-Free statistikasına görə, Swift layihələrində sızmaların 90%-i self-i tutan closures ilə bağlıdır.
Tez-tez verilən suallar
Memory Graph hər iki dil üçün işləyir, çünki Objective-C runtime-dan istifadə edir. ObjC ilə uyğun Swift obyektləri (NSObject varisləri, @objc ilə işarələnmiş) tam göstərilir. ObjC körpüsü olmayan təmiz Swift strukturları və sinifləri məhdud görünür.
Obyektlər Objective-C runtime-da qeydiyyatdan keçməlidir. Swift value types (struct, enum) göstərilmir. Sinfin NSObject-dən varis olduğuna və ya Memory Graph-da görünməsi üçün @objc atributundan istifadə etdiyinə əmin olun.
Mavi — strong reference, obyekti saxlayır. Yaşıl — weak reference, həyat dövrünə təsir etmir. Boz — unowned reference. Retain cycle yalnız mavi kənarlardan əmələ gəlir.
Qrafın qurulması tətbiqi 1–3 saniyə dayandırır və Xcode-un yaddaş istehlakını müvəqqəti olaraq 200–500 MB artıra bilər. Tətbiqin özü yavaşlamır, çünki yoxlama breakpoint-də pauza zamanı baş verir.
Xcode qrafın birbaşa ixracını dəstəkləmir. Sənədləşdirmə üçün ekran görüntüsü və ya lldb skripti heap.find_variable istifadə edin. Ətraflı təhlil üçün Instruments Allocations-dan heap dump ilə istifadə edin.
Nəticə
{} düyünləri kimi göstərir.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.
Həm də oxuyun