Un'app Flutter può sembrare perfetta in debug e poi degradare dopo venti minuti d'uso: frame rate che cala, consumo di RAM che cresce a ogni navigazione, crash OOM sui dispositivi Android di fascia media. Nella quasi totalità dei casi la causa non è il framework, ma oggetti che restano referenziati più a lungo del necessario: AnimationController non dismessi, StreamSubscription mai cancellate, listener registrati su ChangeNotifier globali, closure che catturano un BuildContext o un intero State.
In Dart non esiste un free(): il garbage collector libera solo ciò che non è più raggiungibile. Un leak in Flutter è quindi sempre un problema di grafo di riferimenti. La buona notizia è che oggi abbiamo strumenti di prima classe per vederlo: la vista Memory di DevTools con diff degli snapshot e retaining path, e il pacchetto leak_tracker che Flutter usa internamente e che possiamo attivare nei nostri widget test per far fallire la build quando un oggetto non viene dismesso.
In questo tutorial costruiremo un caso di leak realistico, lo isoleremo con DevTools, lo automatizzeremo in test, lo correggeremo con pattern riutilizzabili e infine renderemo il controllo parte della pipeline CI. Serve dimestichezza con StatefulWidget, stream e ciclo di vita dei widget.