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
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.
| Kenmerk | Android | iOS |
|---|---|---|
| Heap-limiet | 64-512 MB (afhankelijk van apparaat) | Impliciet (systeem) |
| Garbagecollectie | ART (Concurrent, Compact) | ARC (Automatic Reference Counting) |
| Lekmechanisme | GC Root-referenties | Retain cycles (sterke referentiecycli) |
| Resultaat | OutOfMemoryError | Geheugenwaarschuwing → 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.
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.
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.
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.
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.
// 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.
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.
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.
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.
| Tool | Platform | Kenmerk |
|---|---|---|
| LeakCanary | Android | Automatische lekdetectie na destroy |
| Memory Profiler | Android Studio | Heap dump + live allocaties |
| Eclipse MAT | Android | Dominatorboom, Leak Suspects Report |
| Memory Graph | iOS (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
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.
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.
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.
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.
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
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.
Lees ook