Memory leak app mobile: debug
Un memory leak in un'app mobile porta a rallentamenti, crash OutOfMemory e cattiva esperienza utente. Trovarli richiede strumenti specifici e una buona conoscenza dei pattern tipici (retain cycle iOS, listener Android non rilasciati). Vediamo come affrontarli sistematicamente.
Pattern frequenti
iOS: retain cycle tra blocchi e self; closure che catturano fortemente self; observer non rimossi; delegate strong al posto di weak. Android: Activity/Fragment trattenuti da listener statici; Context salvato in oggetti longevi; AsyncTask con riferimenti impliciti; Handler/Runnable non rimossi.
Strumenti iOS
Xcode Instruments offre il template Leaks per individuare object ciclici, Allocations per andamento heap, VM Tracker per pressure di sistema. Memory Graph Debugger consente di esplorare grafo a vista. Combinato con il bug "test e debug" scoprite i leak in pochi minuti.
Strumenti Android
Android Studio Profiler ha la sezione Memory con dump e heap analysis. LeakCanary e la libreria standard per individuare leak in debug: rileva automaticamente Activity destroyed ancora in memoria e produce un report chiaro. Strict Mode integrato segnala pratiche pericolose.
Leak tipici iOS
1) Strong reference cycle tra delegate e parent. 2) Closure che catturano self forte. 3) NotificationCenter observer non rimossi. 4) Timer Foundation che trattengono target. 5) Combine subscription non cancellate (use AnyCancellable e store in Set).
Leak tipici Android
1) Activity trattenute da listener statici. 2) Inner class non statiche di Activity (catturano outer). 3) Handler senza removeCallbacks. 4) BroadcastReceiver non unregister. 5) Singleton con Context Activity invece di ApplicationContext.
Heap analysis avanzata
Su Android, Memory Profiler permette di catturare snapshot e confrontarli (allocations tracking). Cerca instance count crescenti di Activity/Fragment. Su iOS, Memory Graph Debugger mostra il grafo di ownership. Combinato con Instruments Allocations Generations identifica esattamente quale operazione introduce il leak.
LeakCanary in profondita
LeakCanary analizza automaticamente il heap dump quando individua oggetti che dovrebbero essere garbage-collected. Produce stack trace di retain chain. Configurabile per ignorare leak noti di librerie terze. Indispensabile in fase di sviluppo Android.
Strict Mode Android
Abilita StrictMode in debug per individuare cattive pratiche: disk read/write on main thread, network on main thread, leaked Closable, leaked SqliteObject. Configurabile con penaltyDeath per crash su violazione. Strumento gratuito per individuare problemi che diventerebbero crash in produzione su device lenti.
Garbage Collector e tuning
Android usa CMS, G1 a seconda della versione. iOS usa ARC senza GC tradizionale. Su Android, pause di GC lunghe (>100ms) causano jank percepito. Riduci pressure di allocazione: usa StringBuilder, evita autoboxing in hot path, riusa ArrayList con clear(). Per app ad alta performance, profile l'allocazione con Memory Profiler.
Procedura passo-passo
- Integra LeakCanary nelle build debug Android.
- Profila con Instruments (Leaks, Allocations) i flussi critici su iOS.
- Ripeti l'azione sospetta 5-10 volte per accumulare evidenze.
- Esamina il grafo di retain per individuare cicli.
- Correggi con weak/unowned (iOS) o WeakReference (Android).
- Verifica che il fix elimini il leak ripetendo il test.
- Aggiungi test di regressione automatici.
Test automatizzati per leak
LeakCanary supporta test automatici: AppWatcher.watch dopo destroy, verifica nessun retain dopo timeout. Su iOS, weak observer pattern in unit test permette di verificare deinit chiamato. Aggiungi smoke test per scenari critici (login/logout ripetuti, navigation cyclic). Regression test prevengono che nuovi leak entrino in produzione.
Errori comuni e come risolverli
- Closure trattenute: usa [weak self] e guard let self.
- Singleton con Context: usa Application context, mai Activity.
- Observer mai rimossi: rimuoverli in deinit/onDestroy.
- Bitmap grandi: usa Glide/Coil e ridimensiona prima del display.
- Static reference a UI: vietato in pratica.
Domande frequenti
D: LeakCanary funziona anche su release?
R: No, e solo per debug per evitare overhead.
D: Quanto consumo memoria e accettabile?
R: Dipende dal device; sotto i 200 MB per un'app standard e un buon target.
D: Crash OOM si vedono in Crashlytics?
R: Solo parzialmente, perché il processo viene killato dal sistema. Combina con Firebase Performance e device logs.
D: Tutti i memory leak causano crash OOM?
R: No, alcuni causano solo rallentamenti. Ma in scenari di uso prolungato accumulano e prima o poi causano OOM o degrado UX.
Prevenzione vs cura
Prevenire e meno costoso che curare. Code review obbligatoria per Activity, ViewModel, closure con self forte. Linter rules per pattern problematici. Pair programming su funzioni critiche per allocazione/deallocation. Documenta lessons learned di leak storici per evitare ripetizioni. Cultura di ownership della memoria differenzia team mobile maturi.
Memory profiler in azione: cattura snapshot, esegui scenario sospetto, cattura nuovo snapshot, confronta. Filter per Activity, Fragment, ViewModel instances. Verifica count: dovrebbe essere 1 (current); se 2+, hai leak. Su iOS, Memory Graph Debugger visualizza ownership graph. Combina con Instruments Allocations Generations per analisi temporale.
Pattern di prevenzione: ogni listener registrato deve essere unregistered. Ogni observer creato deve essere removed. Ogni Timer deve essere invalidated. Ogni Bluetooth/Network connection deve essere closed. Auto-tracking con strumenti come LeakCanary continuo previene accumulo di problemi nel tempo.
Hai bisogno di aiuto?
Se vuoi sviluppare la tua app con G Tech Group, scrivici tramite il modulo di contatto.