Memory Graph — det visuella verktyget i Xcode Debug Navigator som visar grafen över objekt i applikationens RAM-minne med deras ömsesidiga referenser. Till skillnad från en heap dump, visar Memory Graph inte bara en lista över objekt, utan en riktad referensgraf där varje nod är ett objekt och varje kant är en referens (strong, weak, unowned). Enligt Apple WWDC 2018 gör verktyget det möjligt att visuellt upptäcka retain cycles och minnesläckor på några sekunder, utan att behöva analysera rådata från heap dump.
Huvudpunkter
Memory Graph — är en komponent i Xcode Debug Navigator (introducerad i Xcode 10, WWDC 2018) som bygger en riktad graf över alla objekt i minnet för den process som felsöks. Varje nod i grafen är en klassinstans (Objective-C eller Swift), varje kant är en referens till ett annat objekt. Kantens färg anger referenstypen: blå — strong, grön — weak, grå — unowned. Grafen byggs baserat på data från LLDB och Objective-C runtime, därför måste applikationen vara kompilerad i Debug-konfiguration med aktiverade symboler för korrekt funktion.
Funktionsprincip: när applikationen är pausad vid en brytpunkt begär Xcode via LLDB från runtime alla levande objekt och deras referenser. LLDB använder objc_getClassList och iteration över allokeringsregioner för att bygga den fullständiga grafen. På ARM64 (Apple Silicon) används ytterligare hårdvarumedel för att spåra allokering utan inbromsning. Tiden för att bygga grafen beror på heapens storlek: för en typisk iOS-applikation (50–200 MB) byggs grafen på 1–3 sekunder.
Enligt Apple är Memory Graph det enda verktyget som kan visualisera retain cycles utan kodändringar eller tillägg av instrumentering. Till skillnad från Instruments Leaks fungerar Memory Graph i realtid inuti Xcode och kräver ingen separat start av profileraren. Detta gör det till det första valet för snabb diagnos av minnesläckor i utvecklingsprocessen.
Heap dump ger en tabell över alla objekt med siffror (shallow size, retained size) — den är optimal för kvantitativ analys. Memory Graph ger en visuell bild av kopplingar — den är optimal för att söka efter cykliska referenser. Verktygen kompletterar varandra: först Memory Graph för snabb upptäckt av retain cycles, sedan heap dump via Instruments Allocations för exakt mätning av retained size. Enligt objc.io:s erfarenhet täcker kombinationen av två metoder 95% av minnesläckscenarierna.
Retain cycle — en situation där två eller fler objekt håller fast varandra med starka referenser och bildar en sluten kontur. ARC kan inte frigöra en sådan kontur eftersom retain count för varje objekt aldrig når noll. Klassiskt exempel: ViewController och View, där View har en strong reference till en closure som fångar self (ViewController). Memory Graph visar sådana konturer som ringar (cykler) och markerar dem för snabb identifiering.
När Xcode upptäcker en retain cycle markerar den med en orange kontur och visar en varning i Debug Navigator. Genom att klicka på cykeln ser du kedjan av referenser som bildar den slutna konturen. Det återstår för utvecklaren att avgöra vilken stark kant som ska vara svag — vanligtvis är detta referensen från det underordnade objektet till det överordnade (t.ex. delegate eller closure).
class ViewController: UIViewController {
let service = DataService()
override func viewDidLoad() {
super.viewDidLoad()
// ❌ Retain cycle: ViewController → tjänst → 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
}
}
I Memory Graph ser du en triangel: ViewController → DataService → closure → ViewController. Lösningen — svag fångst av self: [weak self]. Efter korrigeringen visar Memory Graph en grön kant från closure till ViewController och retain cycle försvinner.
// Korrigerad kod — svag fångst av self
service.fetchData { [weak self] data in
guard let self else { return }
self.updateUI(data)
}
Gränssnittet för Memory Graph Debugger består av tre paneler: vänster — lista över alla levande objekt (grupperade efter klass) med antal instanser; mitten — visuell graf med dragbara noder; höger — inspektör för valt objekt eller kant. I objektlistan visas: klassikon, antal instanser i minnet, total retained size och procent av hela heapen. Filtrering efter klassnamn stöder reguljära uttryck.
Grafens noder kan dras för att förbättra läsbarheten. Dubbelklicka på en nod öppnar detaljerad information om objektet: alla dess egenskaper med typer och värden, anropsstack (backtrace) för varje egenskap och retain/release-historik. Backtrace — nyckelfunktion: den visar vilken exakt kodrad som satte referensen till objektet. Detta gör det möjligt att hitta källan till läckan utan att manuellt gå igenom hela koden.
För komplexa grafer tillhandahåller Xcode automatisk layout via Layout → Hierarchical (hierarkisk) eller Cluster (kluster). Hierarkisk layout placerar rotobjekt överst, underordnade objekt längst ner, vilket förenklar sökningen efter kedjor. Klusterlayout grupperar relaterade objekt i kluster, vilket är praktiskt när grafen innehåller flera isolerade grupper. Enligt Apple rekommenderas hierarkisk layout för de flesta applikationer — den är intuitiv och tar mindre tid för visuell analys.
// LLDB-kommandon som Memory Graph använder under huven
(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
Ett systematiskt tillvägagångssätt för Memory Graph-analys omfattar flera steg. Steg 1: starta applikationen, utför ett scenario som potentiellt orsakar en läcka (öppna/stäng skärmen, utför en nätverksbegäran). Steg 2: tryck på Memory Graph-knappen i Debug Navigator — Xcode bygger grafen. Steg 3: kontrollera de orangea retain cycle-varningarna i den vänstra panelen. Steg 4: för misstänkta objekt använd alternativet Show only cycles — endast noder som ingår i cykliska referenser visas.
När en retain cycle har hittats, klicka på cykelns kant och öppna inspektörspanelen. I avsnittet Backtrace visas anropsstacken vid tidpunkten när denna referens sattes. Om kanten till exempel leder från closure till self, visar backtrace i vilken metod och på vilken kodrad closure skapades. Detta eliminerar behovet av att gissa — du ser omedelbart skapelsepunkten för den problematiska referensen. Enligt WWDC Labs minskar backtrace-analys diagnostiden för retain cycle från 15–20 minuter till 2–3 minuter.
class ProfileViewController: UIViewController {
var profileView: ProfileView!
override func viewDidLoad() {
super.viewDidLoad()
profileView = ProfileView()
// Memory Graph visar retain cycle här
profileView.onTap = { [unowned self] in
// ⚠️ unowned kan orsaka krasch vid nil self
self.navigateToDetail()
}
}
func navigateToDetail() { }
}
// ✅ Korrekt: [weak self] + guard let self
profileView.onTap = { [weak self] in
guard let self else { return }
self.navigateToDetail()
}
Memory Graph kan visa tusentals objekt, vilket försvårar sökningen. Använd filter i den vänstra panelen: ange klassnamnet (t.ex. ProfileViewController) för att endast visa instanser av den klassen. Välj sedan instansen som borde ha frigjorts (om skärmen är stängd men objektet finns kvar). Tillämpa Show Reachable From — endast referenser som är relevanta för detta objekt visas, resten av grafen döljs.
Erfarna utvecklare använder Memory Graph inte bara för att hitta läckor, utan också för proaktiv minneskontroll. Kontrollera Memory Graph efter varje större arkitekturförändring — tillägg av ny delegat, closure eller prenumeration på NotificationCenter. Det räcker att utföra ett typiskt scenario och försäkra sig om att objekt frigörs korrekt och att retain cycles saknas. Detta tar 2–3 minuter men förhindrar timmar av senare felsökning.
Memory Report i Xcode (fliken Debug Navigator) visar en graf över minnesförbrukning i realtid. Använd den tillsammans med Memory Graph: öppna Memory Graph vid plötslig ökning av förbrukningen. Vid rullning av en lång lista med celler som laddar bilder, visar Memory Graph till exempel vilka objekt som skapas och vilka som frigörs. Om antalet objekt ökar utan minskning — är detta en potentiell läcka, synlig innan den leder till en krasch. Enligt Apple är kombinationen Memory Graph + Memory Report det rekommenderade arbetsflödet för alla iOS-utvecklare från och med Xcode 12.
// Exempel på läcka i Objective-C via delegering
@interface DownloadManager : NSObject
@property (strong) id delegate; // ❌ Måste vara weak!
@end
@implementation DownloadManager
// Memory Graph visar retain cycle:
// ViewController → DownloadManager.delegate → ViewController
@end
// Korrigering: weak property
@property (weak) id delegate;
Ägna särskild uppmärksamhet åt closures — den vanligaste källan till retain cycles i Swift. Vid fångst av self inuti en closure som lagras som en egenskap hos objektet bildas en klassisk cykel. Memory Graph visar detta som en closure (nod med symbolen {}), kopplad med blå kanter till de fångade objekten. Kontrollera regelbundet alla closures, särskilt de som används i asynkrona anrop, GCD, Combine och SwiftUI. Enligt statistik från Point-Free är 90% av läckorna i Swift-projekt relaterade till closures som fångar self.
Vanliga frågor
Memory Graph fungerar för båda språken eftersom det använder Objective-C runtime. Swift-objekt som är kompatibla med ObjC (arv från NSObject, markerade med @objc) visas fullständigt. Rena Swift-strukturer och klasser utan ObjC-brygga visas begränsat.
Objekt måste vara registrerade i Objective-C runtime. Swift value types (struct, enum) visas inte. Se till att klassen ärver från NSObject eller använder attributet @objc för synlighet i Memory Graph.
Blå — strong reference, håller kvar objektet. Grön — weak reference, påverkar inte livscykeln. Grå — unowned reference. Retain cycle bildas endast av blå kanter.
Att bygga grafen pausar applikationen i 1–3 sekunder och kan tillfälligt öka Xcode-minnesförbrukningen med 200–500 MB. Själva applikationen blir inte långsammare eftersom inspektionen sker under pausen vid brytpunkten.
Xcode stöder inte direkt export av grafen. Använd en skärmbild för dokumentation eller lldb-skriptet heap.find_variable för programmatisk dataextraktion. För detaljerad analys använd Instruments Allocations med heap dump.
Sammanfattning
{}-noder.Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också