Il primo elemento da conoscere è la memoria Heap che è un'area di memoria in cui le applicazioni in esecuzione possono inserire i propri dati in maniera dinamica. La sua dimensione varia in maniera dinamica ma rimane all'interno di un valore massimo chiamato heap size che dipende dal tipo di device. Per comprendere al meglio, un esempio di Heap per il caro vecchio Nexus one (presentato nel 2010) è di 32 MB nonostante i 512 MB di RAM a disposizione.
Vi sono un paio di motivazioni per le quali Android pone questo limite. Una delle grandi caratteristiche di Android è il multitasking, che permette di avere più applicazioni che girano nello stesso momento. Di conseguenza, non è opportuno permettere ad una singola applicazione di utilizzare l'intera memoria del device. Inoltre, i dispositivi devono avere una certa reattività quando si utilizzano più applicazioni.
A causa di questo limite, se una applicazione dovesse richiedere più memoria di quella messa a disposizione dal dispositivo si otterrebbe un errore di Out Of Memory. Essendo la heap size diversa a seconda del device, Android permette di conoscere dinamicamente quanta memoria si ha a disposizione per la propria applicazione. Vi è un metodo che può essere utilizzato nell' ActivityManager: getMemoryClass() che restituisce un valore intero in Megabytes che rappresenta la nostra Heap Size.
Per applicazioni che richiedono maggiore memoria Heap è possibile settare l'attributo largeHeap a true nel proprio Manifest file. In tal caso si può utilizzare il metodo getLargeMemoryClass() per avere una stima della grandezza della memoria a disposizione.
A fronte di questa premessa, un ruolo fondamentale per la gestione automatica della memoria è ricoperto da un "netturbino" cioè il Garbage Collector.
Per Garbage Collection (letteralmente raccolta dei rifiuti, a volte abbreviato con GC) si intende una modalità automatica di gestione della memoria, mediante la quale Android libera le porzioni di memoria che non dovranno più essere successivamente utilizzate dalle applicazioni. In altre parole, il Garbage Collector annoterà le aree di memoria che non sono più referenziate, cioè allocate da un processo attivo, e le
libererà automaticamente. Il principio di funzionamento del Garbage Collector è piuttosto semplice. Si hanno in memoria un insieme di oggetti (indicati con il colore blu in Figura 1). Ogni oggetto può avere un riferimento ad un altro presente nella heap.
Figura 1 - Gli oggetti in memoria |
oggetti chiamati root. Questi oggetti sono sicuramente utilizzati dall'applicazione come per esempio dei riferimenti globali. Partendo da essi, il Garbage Collector visita i nodi del grafo attraverso i vari riferimenti. Al termine di tale processo vi saranno dei nodi non visitati che corrispondono ad oggetti inutilizzati e che, in
seguito, saranno eliminati e la memoria sarà recuperata. E' utile sottolineare come questo processo possa essere eseguito per un lasso di tempo variabile a seconda della heap size. Nelle versioni precedenti quella di Gingerbread l'esecuzione del Garbage Collection comportava una interruzione temporanea dell'esecuzione delle applicazioni. Anche se questa pausa risultava essere piuttosto breve, nell'ordine dei 50-100 millisecondi, col crescere della heap avrebbe potuto portare a delle pause non accettabili per applicazioni con particolari esigenze di reattività. Per tale motivo, nella versione di Gingerbread è stato modi cato il processo di Garbage collection in maniera concorrente rispetto all'esecuzione delle applicazioni ed è stato ridotto il tempo di pausa a 4-5 millisecondi.
A questo punto un problema da non sottovalutare è quello del Memory leak.
Un memory leak è un particolare tipo di consumo non voluto di memoria dovuto alla mancata deallocazione dalla memoria di variabili/dati non più utilizzati da parte dei processi. E' bene precisare che la memoria non viene persa fisicamente, piuttosto diventa inutilizzabile per un difetto del software.
In altre parole, si ha un riferimento ad un oggetto in memoria che la nostra applicazione non utilizzerà più e il Garbage Collector non sarà in grado di ripulire la zona di memoria occupata.
Come si fa a monitorare la memoria e a riconoscere eventuali Memory Leak ?
Esiste un tool chiamato Eclipse Memory Analizyer che mi prometto di recensire nelle mie prossime guide.
Per il momento è meglio affrontare per gradi la questione della gestione della memoria.
Ogni qual volta il Garbage Collector entra in azione viene inviato un messaggio di Log visualizzabile tramite il Logcat. Saper leggere questo messaggio risulta essere fondamentale. Un esempio è mostrato in Figura 2.
Figura 2 - Messaggio di Log del Garbage Collector |
- GC CONCURRENT: Viene eseguita in maniera concorrente quando l'heap comincia a riempirsi.
- GC FOR MALLOC: Non è stato completato GC CONCURRENT in tempo e l'applicazione ha allocato più memoria. L'heap risulta piena e quindi il sistema blocca l'esecuzione dell'applicazione per far spazio al garbage collector.
- GC EXTERNAL ALLOC: Quando viene eseguito il garbage collector nella memoria nativa.
- GC HPROF DUMP HEAP: quando viene creato un HPROF file per l'analisi della memoria tramite il tool Eclipse Memory Analyzer
- GC EXPLICIT: Quando viene richiamato in maniera esplicita l'istruzione System.gc (DA EVITARE)
Nella parte successiva vengono indicate le seguenti informazioni in ordine di visualizzazione:
- Quanta memoria in kb viene liberata in seguito al passaggio del Garbage Collector.
- La percentuale di memoria libera dopo il passaggio del garbage collector.
- Quanta memoria è occupata dagli oggetti presenti nella heap e quant' è la dimensione della heap.
- La dicitura external si riferisce alla memoria nativa. La coppia di dati indica quanta memoria è attualmente occupata e a quanto ammonta il limite imposto dal sistema oltre il quale viene richiamato il processo di Garbage Collector.
- Con la dicitura pause time si indica il tempo di pausa per l'esecuzione del Garbage Collector.
0 commenti:
Posta un commento