Esempi di misurazione e analisi del rendimento

Questi esempi mostrano come utilizzare il tracciamento del sistema con Macrobenchmark, insieme alla profilazione della memoria, per misurare e migliorare determinati tipi di problemi di prestazioni.

Debug dell'avvio dell'app mediante systrace

Per il debug del tempo di avvio, consigliamo di utilizzare i log di systrace. Systrace è un sistema che utilizza codice preinstrumentato per restituire il tempo necessario a determinati eventi quando si verificano. Queste tracce consentono di vedere cosa sta succedendo nell'applicazione o anche in altri processi nel sistema. La piattaforma Android e le librerie Jetpack dispongono di strumentazione per molti eventi chiave in un'applicazione, che vengono registrati di conseguenza. Puoi anche instrumentare le tue applicazioni con tracce personalizzate, che verranno visualizzate negli stessi strumenti di visualizzazione di systrace, per ottenere un quadro generale di ciò che è successo nell'applicazione.

Utilizzo di systrace o Perfetto

Per scoprire di più sull'utilizzo di base di Sytrace, guarda il seguente video: Debug delle prestazioni dell'applicazione.

Per analizzare il tempo di avvio, è necessario innanzitutto capire cosa succede durante l'avvio. Per ulteriori informazioni rispetto a quelle illustrate in questa pagina, la documentazione sul tempo di avvio dell'app offre una panoramica del processo di avvio dell'applicazione.

Le fasi di avvio dell'app sono:

  • Avvia la procedura
  • Inizializzare oggetti di applicazione generici
  • Crea e inizializza attività
  • Espandi il layout
  • Disegna il primo frame

I tipi di avvio prevedono le fasi seguenti:

  • Avvio a freddo: si verifica quando l'applicazione viene avviata per la prima volta dall'avvio o quando il processo dell'applicazione è stato interrotto, da parte dell'utente o del sistema. L'avvio crea un nuovo processo senza stato salvato.
  • Avvio a caldo: si verifica quando l'applicazione è già in esecuzione in background, ma l'attività deve essere ricreata e portata in primo piano. L'attività viene ricreata durante il riutilizzo del processo esistente oppure il processo viene ricreato con lo stato salvato. La libreria di test Macrobenchmark supporta test di avvio tiepido coerenti utilizzando la prima opzione.
  • Avvio rapido: questo si verifica quando il processo e l'attività sono ancora in esecuzione e devono semplicemente essere portati in primo piano, ad esempio ricreando alcuni oggetti se necessario, oltre al rendering della nuova attività in primo piano. Questo è lo scenario di startup più breve.

Ti consigliamo di acquisire le tracce di sistema utilizzando l'app di tracciamento del sistema sul dispositivo disponibile nelle Opzioni sviluppatore. Se vuoi usare strumenti a riga di comando, Perfetto è disponibile con Android 10 (livello API 29) e versioni successive, mentre i dispositivi con versioni precedenti dovrebbero usare systrace.

Nota che il termine "primo frame" è un po' un termine improprio, poiché le applicazioni possono variare significativamente nel modo in cui gestiscono l'avvio dopo aver creato l'attività iniziale. Alcune applicazioni continueranno a crescere per diversi frame, mentre altre verranno lanciate immediatamente in un'attività secondaria.

Se possibile, ti consigliamo di includere una chiamata a reportFullyDrawn (disponibile su Android 10 e versioni successive) al completamento dell'avvio dal punto di vista dell'applicazione.

Ecco alcuni aspetti da cercare in queste tracce di sistema:

Monitora la contesa
Figura 1. La concorrenza per le risorse protette dal monitoraggio può introdurre un ritardo significativo nell'avvio dell'app.

Transazioni binder sincrone
Figura 2. Cerca transazioni non necessarie nel percorso critico della tua applicazione.

garbage collection simultanea
Figura 3. La garbage collection simultanea è comune e ha un impatto relativamente basso, ma se te ne capita spesso, valuta la possibilità di esaminarla con il profiler della memoria di Android Studio.

I/O all'avvio
Figura 4. Controlla la presenza di I/O durante l'avvio e cerca eventuali blocchi lunghi.

Con la figura 4, tieni presente che altri processi che eseguono l'I/O contemporaneamente possono causare una contesa di I/O, quindi assicurati che gli altri processi non siano in esecuzione.

Attività significative su altri thread possono interferire con il thread dell'interfaccia utente, quindi presta attenzione al lavoro in background durante l'avvio. Tieni presente che i dispositivi possono avere configurazioni della CPU diverse, quindi il numero di thread eseguibili in parallelo può variare da un dispositivo all'altro.

Consulta anche la guida sulle fonti comuni di jank

Utilizzare il profiler memoria di Android Studio

Il profilatore di memoria di Android Studio è un potente strumento che riduce la pressione della memoria che potrebbe essere causata da perdite di memoria o pattern di utilizzo non corretti. Fornisce una visione in diretta delle allocazioni e delle raccolte di oggetti.

Per risolvere i problemi di memoria nella tua app, puoi utilizzare il profiler della memoria per monitorare il motivo e la frequenza di garbage collection, nonché se sono presenti possibili perdite di memoria che causano un aumento costante dell'heap nel tempo.

La profilazione della memoria dell'app è suddivisa nei seguenti passaggi:

1. Rileva problemi di memoria

Per rilevare problemi di memoria, inizia registrando una sessione di profilazione della memoria per la tua app. Quindi, cerca un oggetto il cui ingombro della memoria è in aumento, attivando alla fine un evento di garbage collection.

Aumento del conteggio degli oggetti
Figura 5. Profiler di memoria che mostra un aumento delle allocazioni di oggetti nel tempo.

Raccolta rifiuti
Figura 6. Il profiler della memoria che mostra gli eventi di garbage collection.{.:image-caption}

Una volta identificato un caso d'uso che comporta l'aggiunta di pressione in memoria, inizia ad analizzare le cause principali.

2. Diagnosi dei punti sensibili per la pressione della memoria

Seleziona un intervallo nella sequenza temporale per visualizzare sia le allocazioni sia le dimensioni superficiali.

Visualizza le allocazioni e le dimensioni ridotte
Figura 7. Profiler di memoria che mostra le allocazioni e le dimensioni per un intervallo selezionato nella sequenza temporale.

Esistono diversi modi per ordinare questi dati. Le seguenti sezioni forniscono alcuni esempi di come ogni vista può aiutarti ad analizzare i problemi.

Ordinamento per corso

L'organizzazione per classe è utile quando vuoi trovare classi che generano oggetti che altrimenti dovrebbero essere memorizzati nella cache o riutilizzati da un pool di memoria.

Ad esempio, immagina di vedere un'app che crea 2000 oggetti di classe chiamati "Vertex" al secondo. In questo modo il conteggio delle allocazioni aumenta di 2000 al secondo,che potresti visualizzare quando esegui l'ordinamento per classe. Questi oggetti dovrebbero essere riutilizzati per evitare di generare rifiuti? Se la risposta è sì, probabilmente sarà necessario implementare un pool di memoria.

Ordina per sequenza di chiamate

L'organizzazione per chiamate è utile quando c'è un percorso ad accesso frequente in cui viene allocata la memoria, ad esempio all'interno di un loop o di una funzione specifica che esegue molte operazioni di allocazione. La visualizzazione per chiamata ti consentirà di vedere gli hotspot di allocazione.

Dimensioni superficiali e conservate

Dimensioni ridotte tracciano solo la memoria dell'oggetto stesso, pertanto è particolarmente utile per il monitoraggio di classi semplici composte principalmente da primitive.

La dimensione Conservata mostra la memoria totale allocata direttamente dall'oggetto, nonché gli altri oggetti allocati a cui fa riferimento esclusivamente l'oggetto. È utile per monitorare la pressione della memoria dovuta a oggetti complessi che richiedono l'allocazione di altri oggetti e non solo di campi primitivi. Per ottenere questo valore, crea un dump della memoria utilizzando il profiler della memoria. Gli oggetti allocati nell'heap vengono aggiunti alla visualizzazione.

Dump completo della memoria
Figura 8. Puoi creare un dump della memoria in qualsiasi momento facendo clic sul pulsante Esegui il dump dell'heap Java nella barra degli strumenti del profiler della memoria.

aggiunta come colonna
Figura 9. Creando un dump della memoria, viene visualizzata una colonna che mostra le allocazioni di oggetti nell'heap.

3. Misurare l'impatto di un'ottimizzazione

Un miglioramento facile da misurare per l'ottimizzazione della memoria è la garbage collection. Quando un'ottimizzazione riduce la pressione sulla memoria, dovresti vedere meno garbage collection (GC). Per misurarlo, misura il tempo tra i GC nella sequenza temporale del profiler. Dovresti vedere durate più lunghe tra i GC dopo le ottimizzazioni della memoria.

L'impatto finale di miglioramenti della memoria come questi è:

  • L'app verrà chiusa con minore frequenza a causa di problemi di memoria insufficiente se l'app non ha costantemente memoria insufficiente.
  • Avere meno GC migliora le metriche jank. Questo perché i GC causano una contesa della CPU, che può comportare il differimento delle attività di rendering durante l'esecuzione dei GC.