Speicherlecks und Blähung — was es ist, Ursachen und wie man es vermeidet

Autor: IT Sectr Veröffentlicht: 2026-07-28 Lesezeit: 10 Min.

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

  • GC-Erreichbarkeit — ein Objekt wird nicht entfernt, wenn eine aktive Referenz aus dem Wurzelsatz besteht
  • Statische Referenzen auf Activity oder Context — die häufigste Ursache für Lecks in Android
  • LeakCanary — das Standardwerkzeug zur automatischen Leckerkennung in Android
  • WeakReference — eine Lösung für Referenzen, die die Garbage Collection nicht behindern sollen
  • Lifecycle-aware Komponenten kündigen Abonnements automatisch beim Zerstören der View

Was ist ein Speicherleck und eine App-Blähung?

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.

MerkmalAndroidiOS
Heap-Grenze64–512 MB (geräteabhängig)Implizit (System)
Garbage CollectionART (Concurrent, Compact)ARC (Automatic Reference Counting)
LeckmechanismusGC-Root-ReferenzenRetain-Zyklen (starke Referenzzyklen)
ErgebnisOutOfMemoryErrorSpeicherwarnung → 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.

Häufige Speicherleckmuster in Android und iOS

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.

kotlin
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.

  • Handler mit Verzögerung — wenn die Activity zerstört wird, Handler.postDelayed aber noch nicht ausgeführt wurde, leckt die Activity
  • Thread und AsyncTask — bei Bildschirmdrehung wird die Activity neu erstellt, während der alte Thread weiterhin eine Referenz auf die alte Activity hält
  • Retrofit/Callback — ein anonymer Callback hält eine Referenz auf den Presenter oder das Fragment
  • Beobachter — LiveData- oder RxJava-Abonnements ohne Kündigung bei onDestroy

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.

Wie erkennt man Speicherlecks?

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.

kotlin
// 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.

Präventionsstrategien

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.

kotlin
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.

  • Verwenden Sie keine statischen Referenzen auf Context, Activity, View oder Fragment
  • Kündigen Sie alle RxJava-Abonnements in disposeBag / CompositeDisposable bei onDestroy
  • Verwenden Sie [weak self] / [unowned self] in iOS-Closures, um Retain-Zyklen zu verhindern
  • Prüfen Sie Bitmap und große Objekte — sie sollten recycelt oder nullifiziert werden

Speicherprofilierungswerkzeuge

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.

WerkzeugPlattformFunktion
LeakCanaryAndroidAuto-Erkennung von Lecks nach destroy
Memory ProfilerAndroid StudioHeap-Dump + Live-Allocations
Eclipse MATAndroidDominator-Baum, Leak Suspects Report
Memory GraphiOS (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

Was ist der Unterschied zwischen einem Speicherleck und Blähung?

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.

Wie findet LeakCanary Lecks?

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.

Warum verursacht Bitmap häufig OutOfMemoryError?

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.

Was ist ein Retain-Zyklus in iOS?

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.

Wie groß ist der maximale Heap auf Android?

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

  • Speicherleck — ein Objekt, das aufgrund einer aktiven Referenz aus dem Wurzelsatz nicht vom GC gesammelt wird; Blähung — übermäßiger Speicherverbrauch ohne explizite Lecks
  • Statische Referenzen auf Activity, Context oder View — die häufigste Ursache für Lecks in Android; Lösung — WeakReference oder Application Context
  • Anonyme Klassen und Lambdas halten implizit eine Referenz auf die äußere Klasse; nicht gekündigte Callbacks sind die zweithäufigste Ursache
  • LeakCanary — der Standard zur automatischen Leckerkennung in Android; die Integration dauert 5 Minuten und reduziert die Crash-Rate um 30–50%
  • lifecycleScope und viewModelScope brechen Coroutinen bei Zerstörung automatisch ab und eliminieren so eine ganze Klasse von Lecks
  • Retain-Zyklen in iOS werden mit weak/unowned self in Closures und Delegaten gelöst
  • Profilieren Sie den Speicher mindestens einmal pro Sprint — ein Heap-Dump mit MAT oder Memory Graph sollte Teil des Code-Reviews werden

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.

Projekt besprechen

Lesen Sie auch