Un’introduzione alla gestione della memoria e alle fughe di memoria su Android

E’ bene tenere a mente che mentre questo strumento può essere molto utile per trovare riferimenti a una fuga sospetta, può essere abbastanza difficile e complesso da usare per trovare fughe sconosciute e richiede un bel po’ di analisi. Detto questo, se riesci a padroneggiarlo – è un grande strumento da avere sotto la cintura!

LeakCanary

Immagine da LeakCanary

Un altro modo per trovare perdite di memoria è utilizzando Leak Canary, una libreria creata da Square che ti aiuta a rilevare le perdite di memoria. Funziona attraverso l’uso di una classe ObjectWatcher che contiene riferimenti deboli a oggetti distrutti nell’heap. Se il riferimento non viene cancellato nei cinque secondi successivi e il Garbage Collector è stato eseguito, l’oggetto viene considerato conservato e lo registra come una potenziale perdita di memoria nel logcat. Piuttosto intelligente, eh?

Per iniziare, aggiungi semplicemente la libreria tra le tue dipendenze al tuo file build.gradle, sincronizza e compila.

Aggiungi la libreria LeakCanary

Appena avvii l’applicazione, puoi vedere l’output di LeakCanary nel logcat mentre guarda gli istanti e conserva gli oggetti. Per innescare una perdita, ho aggiunto un paio di nuovi compiti nella mia applicazione TaskManager. Non molto tempo dopo, ho ricevuto questa notifica da LeakCanary che indica una potenziale perdita!

Basta cliccare sulla notifica di “dump heap” per indagare sulla potenziale perdita e questa finestra di dialogo verrà visualizzata nell’app.

LeakCanary sta indagando sulle perdite..

Leak Canary analizza quindi l’heap individuando gli oggetti trattenuti e trova la traccia della perdita che è un percorso di riferimenti a ciascun oggetto trattenuto. Una volta fatto, viene visualizzata una notifica che riassume il numero di oggetti trattenuti e le perdite.

Sembra che abbia trovato la nostra perdita! Se ci clicchiamo sopra vedremo la traccia completa della perdita:

Ci sta dicendo che TaskActivity sta perdendo e i riferimenti sottolineati mostrano la traccia, sta perdendo da mContext in SingletonExample – suona familiare! Ora sappiamo come trovare una perdita usando LeakCanary. 😃

Evitare le perdite di memoria

Ora che abbiamo trovato la nostra perdita di memoria, come possiamo evitarla in futuro? Qui sotto ci sono alcune delle cause e dei modelli più comuni.

Foto di Bogomil Mihaylov su Unsplash

Ricevitori broadcast

I ricevitori broadcast possono essere usati per ascoltare eventi o intenti broadcast a livello di sistema che indicano informazioni sul dispositivo come batteria scarica, data e cambiamenti di connettività – per esempio che la modalità aereo è stata disattivata. Quando li usiamo, dobbiamo ricordarci di annullare la registrazione dei ricevitori broadcast, altrimenti inevitabilmente manterremo un riferimento all’attività.

Come evitarlo: Tutto quello che dovete fare è chiamare unregister() sul vostro ricevitore broadcast in onStop() nella vostra attività.

Questo pattern si trova anche per asyncTask, TimerTask e threads che devono essere cancellati in onDestroy() per evitare una perdita.

Context to Singleton class

A volte abbiamo bisogno di passare il contesto da un’attività a una classe Singleton. Un esempio di questo potrebbe essere una classe utils dove abbiamo bisogno di accedere a risorse, servizi o file interni. Tuttavia, passare il contesto significa che inevitabilmente manteniamo un riferimento all’attività.

Come evitarlo: Invece di passare in this da un’attività, possiamo passare nel contesto dell’applicazione se è disponibile (se volete saperne di più su quando usare quale contesto, ho trovato questo articolo molto utile!) Una soluzione alternativa è assicurarsi di impostare il contesto Singleton su null all’interno del metodo activity onDestroy().

Riferimenti statici

Riferire una vista o un’attività come statica significa che il riferimento all’attività non sarà garbage collect. Questo dovrebbe essere semplicemente evitato in ogni momento.

Come evitarlo: Se per qualche ragione dovete farlo, potete assicurarvi che venga distrutto impostandolo a null in onDestroy().

Riferimenti a classi interne

Le classi interne spesso causano perdite tenendo un riferimento implicito alla classe esterna. Questo accade se la variabile di classe è dichiarata come statica o se la classe stessa non è dichiarata come statica. Confusione? Sì, ma è facile da evitare se seguiamo la semplice regola seguente.

Come evitarlo: Rendere la classe interna statica per evitare di tenere un riferimento alla classe esterna e non creare mai una variabile statica di una classe interna. Lo stesso vale per le classi anonime.

Ecco! Spero che abbiate imparato qualcosa sui memory leak e su come evitarli. Buona codifica! 😄

Qui ci sono una serie di articoli e documentazione che ho trovato particolarmente utili per imparare i memory leaks:

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.