Mar 15th, 2025
Una mattina presto alla fine di dicembre 2024, quando la maggior parte di noi era già mentalmente in vacanza per il Capodanno, sono arrivato al lavoro un po' più tardi del solito. Quando sono arrivato in ufficio e stavo appendendo il mio abbigliamento a 20 strati su un appendiabiti, un collega si è rivolto a me e ha detto: «Hai visto l'email?». Io, infastidito: «Quale email?», dato che ho fatto della mia missione di vita evitare di fare cose legate al lavoro a casa. Lui risponde: «Joe di NOME-DELL'AZIENDA- OCCULTATO ci ha mandato un messaggio dicendo che tutti i loro dispositivi sono bloccati o si sono crashati».
Lo scambio di cui sopra segna l'inizio della mia caccia alle perdite di memoria e all'ottimizzazione delle app Flutter, durata due mesi.
Voi, che probabilmente state passando le stesse cose, potreste trovare questa serie di post del blog provvidenziale. In questa serie in 4 parti, delineerò tutto ciò che ho imparato sulle perdite di memoria, le loro cause e come risolverle. Inizierò con un po' di teoria su cosa causa le perdite di memoria e come evitarle, e poi continuerò con i modi per rilevare le perdite di memoria, dalle tecniche più semplici a quelle più avanzate.
Con le informazioni che riceverete, non ci vorranno due mesi per trovare e risolvere le vostre perdite di memoria.
Immagina di stare facendo il check-out da una camera d'albergo, e la receptionist dimentica di segnare la tua camera come vuota. Anche se quella camera è inutilizzata, nessun altro può usarla.
Immagina di allocare un oggetto in un punto della memoria e di dimenticare di liberarlo quando non ne hai più bisogno. Anche se quello spazio di memoria potrebbe essere riutilizzato, nessun altro può usarlo.
Avere un tale oggetto che occupa il tuo spazio di memoria si chiama perdita di memoria.
In breve, le perdite di memoria causano un alto utilizzo della memoria, rallentano le prestazioni, causano crash e, sui dispositivi mobili, consumano più batteria.
Concentriamoci su Flutter e le sue funzionalità di gestione della memoria.
Il linguaggio di programmazione Dart, alla base di Flutter, utilizza un meccanismo di garbage collection generazionale (GC) per gestire l'uso della memoria del sistema.
Utilizza un approccio a due livelli che si occupa rispettivamente degli oggetti a vita breve e degli oggetti a vita lunga:
Diagramma di flusso del processo di garbage collection in Dart
Qualsiasi oggetto senza riferimenti allegati è un obiettivo per il GC di Dart. Se un oggetto ha ancora riferimenti che puntano a esso, anche quando non è più utilizzato, il GC di Dart lo ignorerà, e l'oggetto rimarrà in memoria. Etichettiamoli come oggetti non raccoglibili.
Quindi, devi davvero fare qualcosa? Il garbage collector di Dart fa tutto il lavoro al posto tuo? Dart si occupa delle allocazioni di memoria non utilizzate?
Sì e no.
È vero che, a differenza di
C
, dove devi occuparti di tutte le tue allocazioni di memoria da solo, Dart fa la maggior parte del lavoro pesante per te. Tuttavia, ci sono eccezioni per le quali il GC di Dart non è abbastanza intelligente da occuparsene.
Poiché Dart è un linguaggio orientato agli oggetti, significa che tutto è un oggetto in profondità, anche i tipi primitivi come
int
,
double
,
bool
,
String
e
null
.
A prima vista, te la caverai molto bene se ti occupi di tutti gli oggetti Dart con il metodo dispose su di essi. Lo sviluppatore deve liberare questi oggetti "manualmente" quando l'uso previsto dell'oggetto è terminato.
Ma quanto sopra non copre tutto. Non tutti gli oggetti non raccoglibili hanno un metodo dispose.
Ecco un elenco degli oggetti che più comunemente causano perdite:
Se sei interessato a esempi e modelli su come liberarti degli oggetti non raccoglibili menzionati sopra, vai al
di questa serie.