Es war zwei Uhr morgens, als ein Kollege aus dem Testing einen Vorfall kurz vor dem Absturz schickte: Nach einem Dutzend Mal Rein-und-Raus auf einem bestimmten Screen kletterte der Speicherverbrauch von 80MB bis auf 600MB, bevor das System die App killte. Solche "langsam wachsenden" Leaks lassen sich kaum durch reines Codelesen aufspüren — dafür braucht man Instruments. Das Problem: Unsere lokalen Macs waren permanent mit Simulatoren und Build-Jobs ausgelastet, und eine weitere Instruments-Session drehte die Lüfter auf Hochtouren, während die Daten trotzdem unsauber blieben. Irgendwann haben wir den gesamten Debugging-Workflow auf einen Cloud Mac mini verlegt. Eine dedizierte physische Maschine ohne Nachbarn, die um Ressourcen konkurrieren, liefert deutlich sauberere Traces — hier die genaue Vorgehensweise.
Warum auf einer dedizierten physischen Maschine debuggen
Instruments selbst hat einen ordentlichen CPU- und Speicher-Overhead — das Leaks-Template scannt den Heap periodisch, Allocations protokolliert bei jeder einzelnen Allokation den Call Stack. Läuft der Host als geteilte Umgebung, die im Zeitscheiben-Verfahren mehrere Jobs bedient, mischen sich massenhaft Scheduling-Ausschläge in die Timeline, die mit der eigenen App nichts zu tun haben. Die Kurve wird unsauber, und man produziert leicht falsche "Wachstumspunkte". Der Vorteil einer dedizierten physischen Maschine ist simpel: Fast jeder Speichersprung, den man sieht, lässt sich direkt einer eigenen Aktion zuordnen — man muss nicht erst ausschließen, ob gerade ein fremder Job Ressourcen wegnimmt.
Das Schlimmste bei der Speicherfehlersuche ist nicht, keine Spur zu finden — sondern einen Haufen falscher Spuren. Je mehr Rauschen die Umgebung erzeugt, desto mehr falsche Spuren bekommt man.
Vorbereitung: Bildschirmfreigabe und Versionsabgleich
Sobald der Cloud Mac mini gebootet ist, zuerst über die eingebaute Bildschirmfreigabe (VNC) verbinden. Die Auflösung sollte mindestens 1920x1080 betragen — bei niedrigerer Auflösung quetscht sich die Instruments-Timeline zu einem winzigen Streifen zusammen, in dem sich Details schlicht nicht mehr erkennen lassen.
# Lokales Terminal: erst per SSH prüfen, ob die Instanz erreichbar ist
ssh dev@<deine-instanz-adresse> "sw_vers -productVersion; xcodebuild -version"
# Mit einem VNC-Client verbinden, Adresse ist die der Instanz zugewiesene interne/öffentliche Adresse
open "vnc://dev@<deine-instanz-adresse>"
Nach dem Verbinden zuerst die Xcode-Version mit dem lokalen Entwicklungsrechner abgleichen — insbesondere Versionsunterschiede in der Instruments-Template-Bibliothek können dazu führen, dass neuere Features (etwa Tracing im Zusammenhang mit Swift Concurrency) fehlen. Mit xcode-select -p den Pfad der Kommandozeilen-Tools verifizieren, dann Xcode → Open Developer Tool → Instruments öffnen.
Mit dem Leaks-Template zuerst die Leckstelle finden
Ein neues Profil anlegen, ein Gerät auswählen (entweder ein echtes Gerät, das über den Cloud Mac mini verbunden ist, oder erst einen Simulator zum Reproduzieren) und das Leaks-Template wählen. Leaks scannt im Hintergrund periodisch den Heap-Speicher; rot markiert sind Objekte, die trotz Reference Count von null immer noch existieren — verwaiste Objekte.
Vorgehen:
- Aufnahme starten, in der App die verdächtige Aktion (z. B. wiederholtes Rein- und Rausnavigieren auf einem Screen) 15 bis 20 Mal auslösen;
- Die Leaks-Spur links beobachten und feststellen, welcher Zeitpunkt der roten Markierung zu welcher Aktion gehört;
- Den entsprechenden Leak-Eintrag anklicken — im Extended-Detail-Panel rechts erscheint der Allokations-Call-Stack, der direkt zur konkreten Klasse und Methode führt.
Die Grenze von Leaks: Es meldet nur "bestätigte Leaks". Fälle wie ein NSTimer mit starker Referenz oder eine Closure, die self einfängt — bei denen die Referenzkette technisch intakt ist, logisch aber freigegeben werden sollte — entgehen Leaks meistens. Dafür braucht man Allocations.
Mit Allocations die Wachstumskurve betrachten
Ein neues Profil anlegen, das Allocations-Template wählen und "Record Reference Counts" aktivieren. Dieselbe Aktionsfolge wiederholen und nach jeder Runde manuell auf Mark Generation klicken — das setzt einen Marker auf der Timeline, um bequem zu vergleichen, ob der Speicher nach jeder Runde wieder auf seinen Ausgangswert zurückfällt oder nicht.
Der entscheidende Lesehinweis: Steigt die Speicherkurve über mehrere Runden treppenförmig an, mit ähnlicher Stufenhöhe pro Treppe, kann man ziemlich sicher davon ausgehen, dass ein festes Objekt oder Array bei jeder Aktion etwas akkumuliert. In die Ansicht "All Heap Allocations" wechseln, nach Growth sortieren und die Generationen vergleichen — so lässt sich direkt erkennen, welche Klasse mit stetig steigender Instanzenzahl auffällt.
| Beobachtung | Leaks | Allocations |
|---|---|---|
| Erkennt Closure-/Timer-Retain-Zyklen | Schwach | Stark |
| Lokalisierungsgeschwindigkeit | Schnell, direkt rot markiert | Erfordert Vergleich über mehrere Runden |
| Geeignet für | Erste Triage | Präzise Lokalisierung der Wachstumsquelle |
Kreuzvalidierung mit Memory Graph
Sobald Instruments eine verdächtige Klasse gefunden hat, zurück in Xcode wechseln und Debug Memory Graph ausführen (das Speicher-Icon in der Xcode-Debug-Leiste), ausgelöst nach derselben Aktionsfolge. Memory Graph zeichnet den Referenzgraphen der Objekte; ein lila Ausrufezeichen markiert einen möglichen Retain-Zyklus. Dieser Schritt ist eine zweite Bestätigung der Instruments-Erkenntnisse und zeigt besonders deutlich, "wer wen stark referenziert" — oft anschaulicher als der Instruments-Call-Stack lässt sich damit exakt die betreffende Zeile finden, etwa ein Closure-Capture-Muster wie self.completion = { self.doSomething() }.
Nach der Behebung nicht sofort abschließen, sondern zurück in Allocations wechseln und dieselbe Aktionsfolge erneut ausführen, um zu bestätigen, dass die Kurve zwischen den Mark-Generation-Punkten jetzt flach verläuft statt treppenförmig anzusteigen. Erst dann ist der Fix tatsächlich verifiziert.
Häufige Fallstricke und Checkliste
- Vor der Aufnahme immer erst eine "Aufwärm"-Aktion durchführen (Start, Login und andere einmalige Allokationen) — sonst werden normale Kaltstart-Allokationen fälschlich als Leak interpretiert;
- Das Speicherverhalten unterscheidet sich zwischen Release- und Debug-Build — die finale Schlussfolgerung immer noch einmal in der Release-Konfiguration überprüfen;
- Bricht die Bildschirmfreigabe zum Cloud Mac mini ab und wird neu verbunden, kann die Instruments-Session unterbrochen werden — vor längeren Aufnahmen
caffeinate -inutzen, damit der Ruhezustand des Systems die Aufnahme nicht unterbricht; - Nach jedem Fix mit der Generation-Vergleichsmethode in Allocations gegenprüfen, statt sich allein auf eine Code-Review zu verlassen.
Häufig gestellte Fragen
Reicht ein Cloud Mac mini für Instruments-Profiling aus?
Ja. Instruments erzeugt selbst CPU- und Speicherlast; eine dedizierte physische Maschine ohne Nachbarn liefert saubere Samples, was bei feinen Timelines entscheidend ist.
Stört eine niedrige Bildschirmfreigabe-Auflösung den Workflow?
Sie mindert die Lesbarkeit der Timeline. Mindestens 1920x1080 einstellen und den relevanten Zeitbereich in Instruments vor dem Screenshot vergrößern.
Sollte ich die Maschine sofort nach dem Fund kündigen?
Nein. Erst den Fix auf derselben Instanz testen und prüfen, ob die Allocation-Kurve abflacht, bevor über das Ende der Mietperiode entschieden wird.
portal://order
Jetzt gleich eine Maschine mieten?
Dedizierter physischer Mac mini, Mietbeginn ab einem Tag – in rund 4 Minuten von der Zahlung bis zur Nutzung.