Memory Graph — vizuální nástroj Xcode Debug Navigator, který zobrazuje graf objektů v operační paměti aplikace s jejich vzájemnými referencemi. Na rozdíl od heap dumpu, Memory Graph ukazuje nejen seznam objektů, ale orientovaný graf referencí, kde každý uzel je objekt a každá hrana je reference (strong, weak, unowned). Podle údajů Apple WWDC 2018 nástroj umožňuje vizuálně detekovat retain cycles a úniky paměti během několika sekund, bez nutnosti analýzy surových dat heap dumpu.
Hlavní body
Memory Graph — je součást Xcode Debug Navigator (objevil se v Xcode 10, WWDC 2018), který vytváří orientovaný graf všech objektů v paměti laděného procesu. Každý uzel grafu je instance třídy (Objective-C nebo Swift), každá hrana je reference na jiný objekt. Barva hrany udává typ reference: modrá — strong, zelená — weak, šedá — unowned. Graf je vytvářen na základě dat LLDB a Objective-C runtime, proto pro správnou funkci musí být aplikace zkompilována v konfiguraci Debug s povolenými symboly.
Princip fungování: když je aplikace pozastavena na breakpointu, Xcode prostřednictvím LLDB požádá runtime o všechny živé objekty a jejich reference. LLDB používá objc_getClassList a iteraci přes alokační regiony k vytvoření kompletního grafu. Na ARM64 (Apple Silicon) se dodatečně používají hardwarové prostředky pro sledování alokací bez zpomalení. Doba vytváření grafu závisí na velikosti haldy: pro typickou iOS aplikaci (50–200 MB) se graf vytvoří za 1–3 sekundy.
Podle údajů Apple je Memory Graph jediným nástrojem, který dokáže vizualizovat retain cycles bez úpravy kódu nebo přidání instrumentace. Na rozdíl od Instruments Leaks funguje Memory Graph v reálném čase uvnitř Xcode a nevyžaduje samostatné spuštění profilovače. To z něj dělá nástroj první volby pro rychlou diagnostiku úniků paměti v procesu vývoje.
Heap dump poskytuje tabulku všech objektů s čísly (shallow size, retained size) — je optimální pro kvantitativní analýzu. Memory Graph poskytuje vizuální obraz spojení — je optimální pro hledání cyklických referencí. Nástroje se doplňují: nejprve Memory Graph pro rychlou detekci retain cycles, poté heap dump přes Instruments Allocations pro přesné měření retained size. Podle zkušeností objc.io kombinace obou metod pokrývá 95% scénářů úniků paměti.
Retain cycle — situace, kdy dva nebo více objektů drží jeden druhého silnými referencemi, čímž vytváří uzavřený kontur. ARC nemůže takový kontur uvolnit, protože retain count každého objektu nikdy nedosáhne nuly. Klasický příklad: ViewController a View, kde View má strong reference na closure, který zachytává self (ViewController). Memory Graph zobrazuje takové kontury jako prstence (cykly) a zvýrazňuje je pro rychlou identifikaci.
Když Xcode detekuje retain cycle, zvýrazní ho oranžovým konturem a zobrazí varování v Debug Navigator. Kliknutím na cyklus uvidíte řetězec referencí tvořící uzavřený kontur. Vývojáři zbývá určit, která ze silných hran by měla být slabá — obvykle je to reference z podřízeného objektu na nadřazený (např. delegate nebo closure).
class ViewController: UIViewController {
let service = DataService()
override func viewDidLoad() {
super.viewDidLoad()
// ❌ Retain cycle: ViewController → služba → 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
}
}
V Memory Graph uvidíte trojúhelník: ViewController → DataService → closure → ViewController. Řešením je slabé zachycení self: [weak self]. Po opravě Memory Graph ukáže zelenou hranu od closure k ViewController a retain cycle zmizí.
// Opravený kód — slabé zachycení self
service.fetchData { [weak self] data in
guard let self else { return }
self.updateUI(data)
}
Rozhraní Memory Graph Debugger se skládá ze tří panelů: levý — seznam všech živých objektů (seskupených podle tříd) s počtem instancí; střední — vizuální graf s přetahovatelnými uzly; pravý — inspektor vybraného objektu nebo hrany. V seznamu objektů se zobrazuje: ikona třídy, počet instancí v paměti, celkový retained size a procento celé haldy. Filtrování podle názvu třídy podporuje regulární výrazy.
Uzly grafu lze přetahovat pro zlepšení čitelnosti. Dvojité kliknutí na uzel otevře podrobné informace o objektu: všechny jeho vlastnosti s typy a hodnotami, zásobník volání (backtrace) pro každou vlastnost a historii retain/release. Backtrace — klíčová funkce: ukazuje, který přesně řádek kódu nastavil referenci na objekt. To umožňuje najít zdroj úniku bez ručního prohlížení celého kódu.
Pro složité grafy Xcode poskytuje automatické rozložení pomocí Layout → Hierarchical (hierarchické) nebo Cluster (shlukové). Hierarchické rozložení umísťuje kořenové objekty nahoru, podřízené dolů, což usnadňuje hledání řetězců. Shlukové rozložení seskupuje související objekty do shluků, což je vhodné, když graf obsahuje několik izolovaných skupin. Podle údajů Apple se pro většinu aplikací doporučuje hierarchické rozložení — je intuitivní a vyžaduje méně času pro vizuální analýzu.
// Příkazy LLDB, které Memory Graph používá pod kapotou
(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
Systematický přístup k analýze Memory Graph zahrnuje několik fází. Fáze 1: spusťte aplikaci, proveďte scénář, který potenciálně způsobuje únik (otevřete/zavřete obrazovku, proveďte síťový požadavek). Fáze 2: stiskněte tlačítko Memory Graph v Debug Navigator — Xcode vytvoří graf. Fáze 3: zkontrolujte oranžová varování retain cycles v levém panelu. Fáze 4: pro podezřelé objekty použijte volbu Show only cycles — zobrazí se pouze uzly účastnící se cyklických referencí.
Když je retain cycle nalezen, klikněte na hranu cyklu a otevřete panel inspektoru. V sekci Backtrace je zobrazen zásobník volání v okamžiku, kdy byla tato reference nastavena. Například, pokud hrana vede od closure k self, backtrace ukáže, ve které metodě a na kterém řádku kódu byl closure vytvořen. To eliminuje potřebu hádat — okamžitě vidíte bod vytvoření problematické reference. Podle údajů WWDC Labs analýza backtrace zkracuje dobu diagnostiky retain cycle z 15–20 minut na 2–3 minuty.
class ProfileViewController: UIViewController {
var profileView: ProfileView!
override func viewDidLoad() {
super.viewDidLoad()
profileView = ProfileView()
// Memory Graph zde ukáže retain cycle
profileView.onTap = { [unowned self] in
// ⚠️ unowned může způsobit pád při nil self
self.navigateToDetail()
}
}
func navigateToDetail() { }
}
// ✅ Správně: [weak self] + guard let self
profileView.onTap = { [weak self] in
guard let self else { return }
self.navigateToDetail()
}
Memory Graph může zobrazovat tisíce objektů, což ztěžuje hledání. Používejte filtry v levém panelu: zadejte název třídy (např. ProfileViewController), aby se zobrazily pouze instance této třídy. Poté vyberte instanci, která měla být uvolněna (pokud je obrazovka zavřená, ale objekt zůstal). Aplikujte Show Reachable From — zobrazí se pouze reference relevantní pro tento objekt, zbytek grafu bude skryt.
Zkušení vývojáři používají Memory Graph nejen k hledání úniků, ale také k proaktivní kontrole paměti. Kontrolujte Memory Graph po každé větší změně architektury — přidání nového delegáta, closure nebo odběru NotificationCenter. Stačí provést typický scénář a ujistit se, že objekty jsou správně uvolňovány a retain cycles chybí. To trvá 2–3 minuty, ale předchází hodinám pozdějšího ladění.
Memory Report v Xcode (záložka Debug Navigator) zobrazuje graf spotřeby paměti v reálném čase. Používejte jej spolu s Memory Graph: otevřete Memory Graph při prudkém nárůstu spotřeby. Například při rolování dlouhého seznamu s buňkami načítajícími obrázky Memory Graph ukáže, které objekty se vytvářejí a které se uvolňují. Pokud počet objektů roste bez poklesu — jedná se o potenciální únik, viditelný dříve, než vede k pádu. Podle údajů Apple je kombinace Memory Graph + Memory Report doporučeným workflow pro všechny iOS vývojáře od Xcode 12.
// Příklad úniku v Objective-C přes delegaci
@interface DownloadManager : NSObject
@property (strong) id delegate; // ❌ Mělo by být weak!
@end
@implementation DownloadManager
// Memory Graph ukáže retain cycle:
// ViewController → DownloadManager.delegate → ViewController
@end
// Oprava: weak property
@property (weak) id delegate;
Zvláštní pozornost věnujte closures — nejčastějšímu zdroji retain cycles ve Swiftu. Při zachycení self uvnitř closure, který je uložen jako vlastnost objektu, vzniká klasický cyklus. Memory Graph to zobrazí jako closure (uzel se symbolem {}), spojený modrými hranami se zachycenými objekty. Pravidelně kontrolujte všechny closures, zejména ty použité v asynchronních voláních, GCD, Combine a SwiftUI. Podle statistik Point-Free 90% úniků v Swift projektech souvisí s closures zachycujícími self.
Často kladené otázky
Memory Graph funguje pro oba jazyky, protože používá Objective-C runtime. Swift objekty kompatibilní s ObjC (dědící z NSObject, označené @objc) jsou zobrazeny plně. Čisté Swift struktury a třídy bez ObjC mostu jsou viditelné omezeně.
Objekty musí být registrovány v Objective-C runtime. Swift value types (struct, enum) se nezobrazují. Ujistěte se, že třída dědí z NSObject nebo používá atribut @objc pro viditelnost v Memory Graph.
Modrá — strong reference, drží objekt. Zelená — weak reference, neovlivňuje životní cyklus. Šedá — unowned reference. Retain cycle se tvoří pouze z modrých hran.
Vytváření grafu pozastaví aplikaci na 1–3 sekundy a může dočasně zvýšit spotřebu paměti Xcode o 200–500 MB. Samotná aplikace se nezpomaluje, protože inspekce probíhá během pauzy na breakpointu.
Xcode nepodporuje přímý export grafu. Použijte snímek obrazovky pro dokumentaci nebo skript lldb heap.find_variable pro programové získání dat. Pro podrobnou analýzu použijte Instruments Allocations s heap dumpem.
Shrnutí
{}.Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také