Speicherleck — eines der tückischsten Probleme in der mobilen Entwicklung. Der Speicherverbrauch der App wächst stetig, bis er das vom Betriebssystem festgelegte Limit erreicht, gefolgt von einem OutOfMemoryError oder einer erzwungenen Beendigung. Laut Square Engineering haben etwa 40% der Android-Apps mindestens ein Speicherleck, das nur durch Profiling erkannt werden kann. Lassen Sie uns die Ursachen und Methoden zur Vermeidung von Speicherwachstum untersuchen.
Wichtige Erkenntnisse
Speicherleck — eine Situation, in der ein Objekt, das die App nicht mehr benötigt, weiterhin im Heap gehalten wird, weil eine aktive Referenz aus dem GC-Root-Set noch darauf zeigt. Der Garbage Collector betrachtet ein solches Objekt als lebendig und entfernt es nicht.
Speicherblähung — ein breiteres Problem, bei dem die App mehr Speicher verbraucht als für die Ausführung ihrer aktuellen Aufgaben erforderlich ist. Ursachen: übermäßiges Caching, Objektduplizierung, suboptimale Datenstrukturen und Heap-Fragmentierung.
In Android wird jeder App ein begrenzter Heap zugewiesen (normalerweise 64–512 MB, je nach Gerät und OS-Version). In iOS ist die Grenze weniger streng, aber das System sendet eine Speicherwarnung, wenn die Grenze erreicht wird.
| Merkmal | Android | iOS |
|---|---|---|
| Heap-Grenze | 64–512 MB (geräteabhängig) | Implizit (System) |
| Garbage Collection | ART (Concurrent, Compact) | ARC (Automatic Reference Counting) |
| Leckmechanismus | GC-Root-Referenzen | Retain-Zyklen (starke Referenzzyklen) |
| Ergebnis | OutOfMemoryError | Speicherwarnung → Beendigung |
Laut Facebook Engineering Blog verursachen Speicherlecks ~15% der Crash-Berichte in mobilen Apps. Unter Android kommen ANRs aufgrund häufiger GC-Pausen bei Speichermangel hinzu.
Statische Referenz auf Activity — ein klassisches Android-Leck. Wenn ein statisches Feld oder Singleton eine Referenz auf eine Activity hält, wird diese auch nach finish() nicht vom GC gesammelt, solange das Singleton lebt. Eine Activity ist ein schweres Objekt mit einer View-Hierarchie, Ressourcen und Context.
object LeakHolder {
var activityRef: Activity ?= null // leak: static reference to Activity
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle ?= null) {
super.onCreate(savedInstanceState)
LeakHolder.activityRef = this // ❌ MainActivity will never be GC'd
}
}
Anonyme Klassen und Lambdas — halten implizit eine Referenz auf die äußere Klasse. Wenn ein Runnable oder Callback an einen externen Dienst übergeben wird und die Activity zerstört wird, bleibt das anonyme Klassenobjekt in der Warteschlange und verhindert die Garbage Collection der Activity.
In iOS ist das Hauptproblem Retain-Zyklen: zwei Objekte halten starke Referenzen aufeinander und ARC kann den Referenzzähler für keines von beiden auf Null setzen. Ein typischer Fall: ein Closure, das self stark erfasst, und self, das eine Referenz auf das Closure hält.
LeakCanary — eine Bibliothek von Square zur automatischen Leckerkennung in Android. Nach der Zerstörung einer Activity oder eines Fragments wird geprüft, ob das Objekt vom GC gesammelt wurde. Wenn nicht, wird ein Heap-Dump erstellt und der Leck-Trace angezeigt.
// LeakCanary 2.x — auto-integration via Application
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
// LeakCanary auto-installs in debug build
// via ContentProvider — zero code setup
}
}
// Force check invocation
AppWatcher.objectWatcher.watch(watchedObject, "leak description")
Android Studio Profiler — ein integriertes Tool zur Echtzeit-Speicherüberwachung. Es ermöglicht die Aufnahme eines Heap-Dumps, das Auffinden verdächtiger Objekte (Retained Size > 1 MB) und die Verfolgung des GC-Root-Pfads zu jedem Objekt.
Für iOS verwenden Sie den Xcode Memory Graph Debugger. Er visualisiert den Objektgraphen im Speicher, zeigt Retain-Zyklen und ermöglicht die sofortige Erkennung zirkulärer Referenzen. Instruments > Allocations ist ebenfalls für die Langzeitüberwachung verfügbar.
WeakReference — ein grundlegender Mechanismus für Referenzen, die die Garbage Collection nicht beeinträchtigen sollen. Wenn der GC beschließt, ein Objekt zu sammeln, gibt WeakReference null zurück. Es wird für Callbacks, Listener und Referenzen auf UI-Komponenten aus Hintergrundthreads verwendet.
Lifecycle-aware Komponenten — ein architektonischer Ansatz, der in Android Jetpack (Lifecycle, LiveData, Flow, coroutines) implementiert ist. Abonnements werden automatisch bei onDestroy gekündigt, wodurch die Hauptklasse von Lecks eliminiert wird.
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<List<User>>()
val data: LiveData<List<User>> get() = _data
fun loadData() {
viewModelScope.launch {
val result = repository.fetchData()
_data.postValue(result)
// coroutine auto-cancels on onCleared()
}
}
}
viewModelScope und lifecycleScope — integrierte CoroutineScope in Android, die beim entsprechenden Lebenszyklusereignis abgebrochen werden. Dadurch werden Lecks durch Coroutinen vermieden — das häufigste Szenario in der modernen Android-Entwicklung.
Memory Profiler in Android Studio — das primäre Tool zur Heap-Überwachung. Es zeigt Live-Allocations, Heap-Snapshots und Objektzahlen nach Typ. Es ermöglicht die Aufnahme eines Dumps und dessen Analyse in MAT (Memory Analyzer Tool) zum Auffinden verdächtiger Objekte.
Eclipse MAT — ein Desktop-Heap-Dump-Analysator. Nach dem Laden einer HPROF-Datei aus Android Studio erstellt MAT einen Dominator-Baum, zeigt die Retain-Größe jedes Objekts und bietet eine automatische Analyse verdächtiger Lecks über den Leak Suspects Report.
Xcode Memory Graph — ein visueller Retain-Zyklus-Debugger. Beim Klicken auf die Memory Graph Debugger-Taste stoppt Xcode die App, erstellt einen vollständigen Objektgraphen im Speicher und hebt Retain-Zyklen rot hervor.
| Werkzeug | Plattform | Funktion |
|---|---|---|
| LeakCanary | Android | Auto-Erkennung von Lecks nach destroy |
| Memory Profiler | Android Studio | Heap-Dump + Live-Allocations |
| Eclipse MAT | Android | Dominator-Baum, Leak Suspects Report |
| Memory Graph | iOS (Xcode) | Retain-Zyklus-Visualizer |
Laut Google I/O 2023 reduzieren Apps, die LeakCanary in Debug-Builds verwenden, speicherbedingte Abstürze in den ersten 2 Monaten nach der Einführung um 30–50%. Es wird empfohlen, LeakCanary bereits in der Onboarding-Phase des Projekts hinzuzufügen.
Häufig gestellte Fragen
Leck — Objekte, die für den Code nicht erreichbar sind, aber aufgrund aktiver Referenzen nicht vom GC gesammelt werden. Blähung — die App hält logisch benötigte Objekte in übermäßiger Menge (z.B. ein 50 MB Cache in einer 80 MB laufenden App). Blähung wird architektonisch behoben, Lecks durch korrektes Referenzmanagement.
LeakCanary verwendet ObjectWatcher — nach onDestroy() einer Activity erstellt es eine WeakReference auf die Activity und führt GC aus. Wenn die WeakReference nach 5 Sekunden nicht gelöscht ist, erstellt LeakCanary einen Heap-Dump, analysiert die kürzeste Referenzkette vom GC Root zum Objekt und zeigt den genauen Leck-Stack mit Datei und Zeilennummer an.
Bitmap belegt Speicher außerhalb des Java-Heaps im nativen Speicher (Native Heap). Die Größe einer Bitmap = Breite × Höhe × 4 Bytes (ARGB_8888). Ein 12 MP Foto (4000×3000) belegt 48 MB. Android kann nativen Speicher nicht immer rechtzeitig freigeben, sodass die Ansammlung mehrerer Bitmaps selbst bei ausreichendem Java-Heap zu OOM führt.
Retain-Zyklus — eine Situation in ARC, in der zwei Objekte starke Referenzen aufeinander halten und der Referenzzähler nie Null erreicht. Ein typisches Beispiel: ein ViewController mit einer starken Referenz auf ein Closure, und das Closure erfasst self stark. Lösung: Verwenden Sie [weak self] oder [unowned self] in Closures.
Die Heap-Größe hängt vom Gerät und der Android-Version ab. Für ältere Geräte (API 15–24) — 64–128 MB. Für moderne (API 25+) — 256–512 MB. Der genaue Wert kann über ActivityManager.getMemoryClass() ermittelt werden. Für große Apps (Spiele, Editoren) bietet largeHeap=true im Manifest bis zu 1 GB.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch