Vreet geheugen en zwelt op — wat is het, oorzaken en hoe te vermijden

Auteur: IT Sectr Gepubliceerd: 2026-07-28 Leestijd: 10 min

Geheugenlek — een van de meest verraderlijke problemen in mobiele ontwikkeling. Het geheugen van de app groeit gestaag tot het de limiet bereikt die door het besturingssysteem is ingesteld, waarna een OutOfMemoryError of gedwongen beëindiging volgt. Volgens Square Engineering heeft ongeveer 40% van de Android-apps ten minste één geheugenlek dat alleen bij profilering kan worden ontdekt. Laten we de oorzaken en preventiemethoden van geheugengroei bespreken.

Belangrijkste punten

  • GC reachability — een object wordt niet verwijderd als er een actieve referentie vanuit de wortelverzameling is
  • Statische referenties naar Activity of Context — de meest voorkomende lekoorzaak in Android
  • LeakCanary — de standaard tool voor automatische lekdetectie in Android
  • WeakReference — de oplossing voor referenties die garbagecollectie niet mogen belemmeren
  • Lifecycle-aware componenten annuleren automatisch abonnementen bij vernietiging van de view

Wat is een geheugenlek en opzwelling van de app?

Geheugenlek (memory leak) — een situatie waarin een object dat niet langer nodig is voor de app, in de heap blijft omdat er een actieve referentie vanuit de wortelverzameling (GC Root) bestaat. De garbage collector beschouwt zo'n object als levend en verwijdert het niet.

Geheugenopzwelling (memory bloat) — een breder probleem waarbij de app meer geheugen verbruikt dan nodig is voor de huidige taken. Oorzaken: overmatig cachen, duplicatie van objecten, suboptimale datastructuren en heap-fragmentatie.

In Android krijgt elke app een beperkte heap toegewezen (meestal 64-512 MB afhankelijk van het apparaat en de OS-versie). In iOS is de beperking minder streng, maar het systeem stuurt een geheugenwaarschuwing bij het naderen van de limiet.

KenmerkAndroidiOS
Heap-limiet64-512 MB (afhankelijk van apparaat)Impliciet (systeem)
GarbagecollectieART (Concurrent, Compact)ARC (Automatic Reference Counting)
LekmechanismeGC Root-referentiesRetain cycles (sterke referentiecycli)
ResultaatOutOfMemoryErrorGeheugenwaarschuwing → beëindiging

Volgens Facebook Engineering Blog zijn geheugenlekken de oorzaak van ~15% van de crashrapporten in mobiele apps. In Android komen daar ANR's bij door frequente GC-pauzes bij geheugentekort.

Typische geheugenlekpatronen in Android en iOS

Statische referentie naar Activity — de klassieker onder Android-lekken. Als een statisch veld of singleton een referentie naar een Activity bewaart, wordt deze niet door GC verzameld, zelfs niet na finish(), zolang de singleton leeft. Activity is een zwaar object met een View-hiërarchie, resources en Context.

kotlin
object LeakHolder {
    var activityRef: Activity ?= null // lek: statische referentie naar Activity
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle ?= null) {
        super.onCreate(savedInstanceState)
        LeakHolder.activityRef = this // ❌ MainActivity zal nooit door GC worden verzameld
    }
}

Anonieme klassen en lambda's — houden impliciet een referentie naar de buitenste klasse vast. Als een Runnable of Callback aan een externe service wordt doorgegeven en de Activity wordt vernietigd, blijft het anonieme klasseobject in de wachtrij hangen en laat de Activity niet door GC verzamelen.

  • Handler met vertraging — als de Activity is vernietigd maar Handler.postDelayed nog niet is uitgevoerd, lekt de Activity
  • Thread en AsyncTask — bij schermrotatie wordt de Activity opnieuw aangemaakt, maar de oude Thread houdt een referentie naar de oude Activity vast
  • Retrofit/Callback — een anonieme Callback houdt een referentie naar de presenter of fragment vast
  • Observers — LiveData- of RxJava-abonnementen zonder opzegging bij onDestroy

In iOS is het grootste probleem retain cycles: twee objecten houden sterke referenties naar elkaar vast en ARC kan de referentieteller voor geen van beiden op nul krijgen. Typisch geval: een closure die self sterk capturet, en self die een referentie naar de closure vasthoudt.

Hoe detecteer ik geheugenlekken?

LeakCanary — een bibliotheek van Square voor automatische lekdetectie in Android. Na vernietiging van een Activity of Fragment controleert het of het object door GC is verzameld. Zo niet, dan maakt het een heap dump en toont de lektrace.

kotlin
// LeakCanary 2.x — auto-integratie via Application
class ExampleApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // LeakCanary installeert zichzelf automatisch in debug build
        // via ContentProvider — nul code configuratie
    }
}

// Forceer controle-aanroep
AppWatcher.objectWatcher.watch(watchedObject, "leak description")

Android Studio Profiler — de ingebouwde tool voor realtime geheugenmonitoring. Maakt het mogelijk een heap dump op te nemen, verdachte objecten (Retained Size > 1 MB) te vinden en het GC-rootpad naar elk object te traceren.

Voor iOS gebruikt u Xcode Memory Graph Debugger. Het visualiseert de objectgraaf in het geheugen, toont retain cycles en maakt het mogelijk circulaire referenties onmiddellijk te detecteren. Ook beschikbaar is Instruments > Allocations voor langetermijnmonitoring.

Preventiestrategieën voor lekken

WeakReference — het basismechanisme voor referenties die garbagecollectie niet mogen belemmeren. Als GC besluit het object te verwijderen, retourneert WeakReference null. Wordt gebruikt voor callbacks, listeners en referenties naar UI-componenten vanuit achtergrondthreads.

Lifecycle-aware componenten — een architecturale benadering geïmplementeerd in Android Jetpack (Lifecycle, LiveData, Flow, coroutines). Abonnementen worden automatisch geannuleerd bij onDestroy, wat de belangrijkste lekklasse elimineert.

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 annuleert zichzelf automatisch bij onCleared()
        }
    }
}

viewModelScope en lifecycleScope — ingebouwde CoroutineScopes in Android die worden geannuleerd bij de corresponderende levenscyclusgebeurtenis. Dit elimineert lekken via coroutines — het meest voorkomende scenario in moderne Android-ontwikkeling.

  • Gebruik geen statische referenties naar Context, Activity, View of Fragment
  • Zeg alle RxJava-abonnementen op in disposeBag / CompositeDisposable bij onDestroy
  • Gebruik [weak self] / [unowned self] in iOS-closures om retain cycles te voorkomen
  • Controleer Bitmaps en grote objecten — ze moeten worden gerecycled of genulled

Tools voor geheugenprofilering

Memory Profiler in Android Studio — de belangrijkste tool voor heap-monitoring. Toont live allocaties, heap-snapshots, het aantal objecten per type. Maakt het mogelijk een dump op te nemen en te analyseren in MAT (Memory Analyzer Tool) voor het vinden van verdachte objecten.

Eclipse MAT — een desktop-analysator voor heap dumps. Na het laden van een HPROF-bestand uit Android Studio bouwt MAT een dominatorboom, toont de retain size van elk object en biedt automatische analyse van verdachte lekken via Leak Suspects Report.

Xcode Memory Graph — een visuele debugger voor retain cycles. Bij het klikken op de Memory Graph Debugger-knop stopt Xcode de app, bouwt een volledige objectgraaf in het geheugen en markeert retain cycles in het rood.

ToolPlatformKenmerk
LeakCanaryAndroidAutomatische lekdetectie na destroy
Memory ProfilerAndroid StudioHeap dump + live allocaties
Eclipse MATAndroidDominatorboom, Leak Suspects Report
Memory GraphiOS (Xcode)Retain cycle-visualisator

Volgens Google I/O 2023 verminderen apps die LeakCanary gebruiken in debug-builds het aantal geheugengerelateerde crashes met 30-50% in de eerste 2 maanden na implementatie. Het wordt aanbevolen LeakCanary toe te voegen in de onboardingfase van het project.

Veelgestelde vragen

Wat is het verschil tussen een geheugenlek en opzwelling?

Lek — objecten die niet toegankelijk zijn voor code maar niet door GC worden verwijderd vanwege actieve referenties. Opzwelling — de app houdt objecten in het geheugen die logisch nodig zijn maar in overmatige hoeveelheid (bijv. 50 MB cache bij een werkende app van 80 MB). Opzwelling wordt architecturaal behandeld, een lek — door correct referentiebeheer.

Hoe vindt LeakCanary lekken?

LeakCanary gebruikt ObjectWatcher — na onDestroy() van een Activity maakt het een WeakReference naar de Activity en start GC. Als na 5 seconden de WeakReference niet is gewist, maakt LeakCanary een heap dump, analyseert de kortste referentieketen van GC Root naar het object en toont de exacte lekstack met bestandsnaam en coderegel.

Waarom veroorzaakt Bitmap vaak OutOfMemoryError?

Bitmap neemt geheugen in beslag buiten de Java heap in native geheugen (native heap). Grootte van één Bitmap = breedte × hoogte × 4 bytes (ARGB_8888). Een 12 MP foto (4000×3000) neemt 48 MB in beslag. Android kan niet altijd tijdig native geheugen vrijmaken, wat bij ophoping van meerdere Bitmaps leidt tot OOM, zelfs met voldoende Java heap.

Wat is een retain cycle in iOS?

Retain cycle — een situatie in ARC waarbij twee objecten sterke referenties naar elkaar vasthouden en de referentieteller nooit nul bereikt. Typisch voorbeeld: een ViewController met een sterke referentie naar een closure, en de closure capturet self sterk. Oplossing: gebruik [weak self] of [unowned self] in closures.

Wat is de maximale heapgrootte in Android?

De heap-grootte hangt af van het apparaat en de Android-versie. Voor oude apparaten (API 15-24) — 64-128 MB. Voor moderne (API 25+) — 256-512 MB. De exacte waarde kan worden verkregen via ActivityManager.getMemoryClass(). Voor grote apps (games, editors) is er largeHeap=true in het manifest, wat tot 1 GB geeft.

Samenvatting

  • Geheugenlek — object niet verwijderd door GC vanwege een actieve referentie uit de wortelverzameling; opzwelling — overmatig geheugenverbruik zonder duidelijke lekken
  • Statische referenties naar Activity, Context, View — nummer één onder lekoorzaken in Android; oplossing — WeakReference of Application Context
  • Anonieme klassen en lambda's houden impliciet een referentie naar de buitenste klasse vast; niet-opgezegde callbacks — de tweede meest voorkomende oorzaak
  • LeakCanary — de standaard voor automatische lekdetectie in Android; integratie duurt 5 minuten en verlaagt het crashpercentage met 30-50%
  • lifecycleScope en viewModelScope annuleren automatisch coroutines bij destroy, waardoor een hele klasse lekken wordt geëlimineerd
  • Retain cycles in iOS worden opgelost met weak/unowned self in closures en delegates
  • Profileer het geheugen minstens één keer per sprint — heap dump met MAT of Memory Graph moet deel uitmaken van code review

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook