Ogni volta che l'applicazione crea un nuovo thread, il sistema operativo deve allocare memoria per supportarlo. Sebbene i thread siano generalmente considerati "leggeri" rispetto ai processi completi, il loro costo in termini di memoria non è pari a zero. La perdita di thread è un modo molto comune di perdere memoria su Android.
Il costo di un thread
Quando viene creato un thread su Android, due componenti principali consumano memoria:
- Stack nativo: la libreria
pthreadalloca uno stack per il thread per archiviare le variabili locali e i frame di chiamata. Su Android, il valore predefinito è in genere 1 MB. - Strutture JVM/kernel interne: ART e il kernel Linux
devono allocare strutture di dati (come gli oggetti
pthread_internal_tejava.lang.Thread) per monitorare e gestire il thread.
Memoria stack e mmap
È importante capire che Android alloca lo stack nativo da 1 MB utilizzando mmap con i flag MAP_ANONYMOUS | MAP_NORESERVE.
Ciò significa che il sistema operativo riserva 1 MB di spazio di indirizzi di memoria virtuale, ma non alloca immediatamente 1 MB di RAM fisica. La memoria fisica viene allocata (paged in) solo quando il thread esegue effettivamente il codice e inserisce i dati nello stack. Un thread che non esegue alcuna operazione consumerà pochissima RAM fisica per il suo stack.
Esercizio pratico: thread con leak
Utilizzeremo l'applicazione di esempio MemoryLab per osservare cosa succede quando un'applicazione crea centinaia di thread inattivi.
1. Lancio e riferimento
Avvia l'app ed esegui una lettura della memoria di base:
adb shell am start -W -n com.android.memorylab/.MainActivity
adb shell dumpsys meminfo -s com.android.memorylab
Osserva le righe Stack e Native Heap nell'output. Probabilmente saranno
piccoli.
2. Crea 100 thread
Tocca il pulsante Crea 100 thread. L'applicazione genererà 100 nuovi thread. Per garantire che la memoria dello stack venga effettivamente impaginata nella RAM fisica (in modo da poterla vedere nei nostri strumenti), ogni thread alloca e scrive in un piccolo array da 10 kB sul proprio stack prima di iniziare l'attesa.
Esegui di nuovo il comando meminfo mentre i thread sono attivi:
adb shell dumpsys meminfo -s com.android.memorylab
I risultati:
Confronta il nuovo output con la base di riferimento. Noterai aumenti significativi mentre i thread sono attivi:
Stack: aumentato di un megabyte o più. Rappresenta le pagine fisiche allocate per i 100 stack di thread (ognuno dei quali tocca almeno 10 kB).Native Heap/Private Other: aumentato a causa delle strutture interne dipthreadallocate dal sistema per ogni thread.
Per eseguire la pulizia, tocca il pulsante Elimina tutti i thread.
3. Visualizzazione dei thread in Perfetto
Perfetto è eccellente per monitorare i cicli di vita e i conteggi dei thread nel tempo.

PerfettoSQL per l'analisi dei thread
Puoi eseguire una query sulla traccia per contare esattamente quanti thread sono stati generati dall'applicazione:
SELECT p.name AS process_name, COUNT(t.id) as thread_count
FROM thread t JOIN process p USING (upid)
WHERE p.name = 'com.android.memorylab' AND t.name LIKE 'LeakedThread-%';
Una query come questa può essere utilizzata per generare una traccia di debug con un contatore, come mostrato nello screenshot.
← Codice app | ↑ Su | Località →