Het is de moeite waard om in gedachten te houden dat, terwijl dit hulpmiddel zeer nuttig kan zijn voor het vinden van verwijzingen naar een vermoedelijk lek, het vrij moeilijk en complex kan zijn om te gebruiken voor het vinden van onbekende lekken en het vereist een behoorlijke analyse. Dat gezegd hebbende, als je het onder de knie hebt – is het een geweldig hulpmiddel om onder de knie te hebben!
LeakCanary
Een andere manier om geheugenlekken te vinden is door gebruik te maken van Leak Canary, een bibliotheek gemaakt door Square die je helpt om geheugenlekken op te sporen. Het werkt met behulp van een ObjectWatcher
-klasse die zwakke verwijzingen naar vernietigde objecten in de heap vasthoudt. Als de verwijzing niet wordt gewist in de volgende vijf seconden en de Garbage Collector heeft gedraaid, wordt het object als behouden beschouwd en logt dit als een potentieel geheugenlek in de logcat. Best slim, hè?
Om aan de slag te gaan, voegt u gewoon de bibliotheek toe aan uw build.gradle-bestand, synchroniseert u en compileert u.
Zodra je de applicatie start, kun je de uitvoer van LeakCanary in de logcat zien terwijl het naar instants kijkt en objecten vasthoudt. Om een lek te veroorzaken, voegde ik een paar nieuwe taken toe in mijn TaskManager-app. Niet lang daarna kreeg ik deze melding van LeakCanary die wijst op een potentieel lek!
Klik op de melding om “dump heap” om het potentiële lek te onderzoeken en dit dialoogvenster wordt weergegeven in de app.
Leak Canary analyseert vervolgens de heap door de vastgehouden objecten te lokaliseren en vindt het lekspoor dat een pad is van verwijzingen naar elk vastgehouden object. Zodra dit is gebeurd, wordt een melding weergegeven met een samenvatting van het aantal vastgehouden objecten en lekken.
Het vertelt ons dat TaskActivity lekt en de onderstreepte referenties tonen het spoor, het lekt van mContext
in SingletonExample
– klinkt bekend! Nu weten we hoe we een lek kunnen vinden met LeakCanary. 😃
Vermijden van geheugenlekken
Nu we ons geheugenlek hebben gevonden, hoe kunnen we ze in de toekomst vermijden? Hieronder staan enkele van de meest voorkomende oorzaken en patronen.
Broadcast-ontvangers
Broadcast-ontvangers kunnen worden gebruikt om te luisteren naar systeembrede broadcast-gebeurtenissen of -intenties die apparaatinformatie aangeven, zoals een lege batterij, datum en connectiviteitswijzigingen – bijvoorbeeld dat vliegtuigmodus is uitgeschakeld. Wanneer we ze gebruiken, moeten we niet vergeten om broadcast ontvangers te de-registreren, anders houden we onvermijdelijk een verwijzing naar de activiteit vast.
Hoe dit te voorkomen: Het enige wat u hoeft te doen is unregister()
aan te roepen op uw broadcast-ontvanger in onStop()
in uw activiteit.
Dit patroon wordt ook gevonden voor asyncTask, TimerTask en threads die moeten worden geannuleerd in onDestroy()
om een lek te voorkomen.
Context naar Singleton-klasse
Soms moeten we context doorgeven van een activiteit aan een Singleton-klasse. Een voorbeeld hiervan zou een utils klasse zijn waar we resources, services of interne bestanden moeten benaderen. Echter, het doorgeven van context betekent dat we onvermijdelijk een verwijzing naar de activiteit vasthouden.
Hoe dit te vermijden: In plaats van this
van een activiteit door te geven, kunnen we applicatiecontext doorgeven als die beschikbaar is (als je meer wilt leren over wanneer je welke context moet gebruiken, vond ik dit artikel erg nuttig!). Een alternatieve oplossing is om de Singleton context op null te zetten in de activity onDestroy()
method.
Static references
Referencing a view or an activity as static means the reference to the activity will not be garbage collected. Dit moet te allen tijde worden vermeden.
Hoe dit te vermijden: Als u het om de een of andere reden toch moet doen, kunt u ervoor zorgen dat het wordt vernietigd door het op null te zetten in onDestroy().
Inner class references
Inner classes veroorzaken vaak lekken door een impliciete verwijzing naar de outer class vast te houden. Dit gebeurt als de variabele van de klasse als statisch wordt gedeclareerd of als de klasse zelf niet als statisch wordt gedeclareerd. Verwarrend? Ja, maar het is gemakkelijk te vermijden als we de eenvoudige regel hieronder volgen.
Hoe het te vermijden: Maak de binnenste klasse statisch om te voorkomen dat je een verwijzing naar de buitenste klasse vasthoudt en maak nooit een statische variabele van een binnenste klasse. Hetzelfde geldt voor anonieme klassen.
Dat was het! Hopelijk heb je wat geleerd over geheugenlekken en hoe je ze kunt vermijden. Veel plezier met coderen! 😄
Hier zijn een aantal artikelen en documentatie die ik bijzonder nuttig vond bij het leren over geheugenlekken: