Profiling è il processo di misurazione delle prestazioni di un'applicazione in base a metriche chiave: carico della CPU, consumo di memoria, traffico di rete e utilizzo di energia. L'obiettivo del profiling è trovare i colli di bottiglia che rallentano l'applicazione o causano un consumo eccessivo di risorse. Secondo Android Developers, il profiling regolare durante lo sviluppo riduce il numero di bug di prestazioni in produzione fino al 60% e aiuta a mantenere un'interfaccia fluida anche su dispositivi di fascia bassa.
Punti Chiave
Profiling è la raccolta e l'analisi dei dati su come funziona un'applicazione: quali funzioni vengono eseguite, quanto tempo impiegano, quanta memoria consumano e come interagiscono con la rete. A differenza del logging, il profiling opera a livello di sistema e fornisce metriche numeriche precise, non valutazioni soggettive.
L'obiettivo principale del profiling è trovare sezioni di codice che utilizzano le risorse in modo subottimale. Questi possono essere metodi lenti chiamati nel thread dell'interfaccia utente, perdite di memoria, query SQL inefficienti, chiamate di rete eccessive o un consumo eccessivo di energia. Senza profiling, gli sviluppatori correggono ciò che “sembra lento” invece di basarsi su dati reali.
Secondo Google I/O 2023, le applicazioni che vengono sottoposte a profiling regolare durante lo sviluppo mostrano il 40% in meno di errori ANR (Application Not Responding) e il 50% in meno di crash OutOfMemory. Gli strumenti di profiling sono integrati in tutti gli IDE moderni — Android Studio Profiler per Android e Xcode Instruments per iOS.
Il profiling può essere statico (analisi del codice senza esecuzione — lint, Detekt) e dinamico (misurazioni durante l'esecuzione dell'applicazione). Per trovare problemi reali di prestazioni, viene utilizzato il profiling dinamico, che mostra il comportamento effettivo dell'applicazione su un dispositivo o emulatore.
Il profiling è necessario prima di ogni rilascio importante, quando si introducono componenti dell'interfaccia pesanti (elenchi, animazioni, viste personalizzate), quando gli utenti lamentano lentezza e consumo della batteria, e dopo aver modificato l'architettura dell'applicazione. Un approccio sistematico consiste nell'eseguire il profiling a ogni sprint, registrando una baseline delle metriche.
Profiling della CPU traccia quali metodi e thread stanno caricando il processore e quanto tempo impiega l'esecuzione di ogni chiamata. L'obiettivo principale è trovare funzioni che vengono eseguite più a lungo del previsto e bloccano il thread dell'interfaccia, causando cadute di fotogrammi (jank) e ANR.
Su Android, il CPU Profiler mostra un albero Top-Down — un albero di chiamate dove è possibile vedere quale metodo viene eseguito più a lungo nel contesto di un thread specifico. Su iOS, Instruments Time Profiler funziona tramite campionamento: a intervalli regolari (ad esempio, 1 ms), il sistema registra lo stack di chiamate di ogni thread. Le statistiche di campionamento determinano quale codice consuma più tempo.
// Esempio: un metodo lento che causa jank
class UserAdapter : RecyclerView.Adapter<UserViewHolder>() {
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
// ❌ Questo metodo viene chiamato nel thread dell'interfaccia e blocca il rendering
// Il profiling mostrerà che decompressImage occupa l'80% del tempo
val user = getItem(position)
val bitmap = ImageUtils.decompressImage(user.avatar)
holder.avatarView.setImageBitmap(bitmap)
}
}
Durante il profiling della CPU, prestare attenzione ai metodi con Self Time elevato — questo è il tempo che un metodo dedica al proprio lavoro, senza contare le chiamate ai metodi figli. Se il Self Time di un metodo nel thread dell'interfaccia supera 16 ms, garantisce una caduta di fotogramma su uno schermo a 60 FPS. La soluzione è spostare le operazioni pesanti in un thread in background.
Profiling della memoria traccia quanta memoria utilizza un'applicazione: quali oggetti vengono creati, quanto vivono e quando vengono liberati. L'obiettivo principale è trovare perdite (oggetti che non dovrebbero esistere ma rimangono in memoria) e allocazioni eccessive (oggetti creati troppo frequentemente).
Su Android, il Memory Profiler mostra un grafico del consumo di RAM in tempo reale, un elenco di tutti gli oggetti allocati e dettagli per ogni tipo. Metriche chiave: Java Heap (oggetti nell'heap JVM), Native Heap (allocazioni a livello C/C++), Graphics Memory (texture e buffer GPU). Per iOS, Instruments Allocations mostra metriche simili: Heap Allocations (oggetti nell'heap) e Anonymous VM (pagine di memoria virtuale).
| Metrica | Android Profiler | Instruments (iOS) |
|---|---|---|
| Oggetti heap | Java Heap + Native Heap | Heap Allocations |
| Grafica | Graphics Memory | VM Tracker |
| Perdite | Memory Profiler + LeakCanary | Leaks instrument |
| Dump dell'heap | HPROF (Capture) | Heapshot |
Durante il profiling della memoria, è importante acquisire dump dell'heap dopo l'esecuzione di scenari tipici dell'utente: aprire e chiudere una schermata, caricare un elenco, lavorare con le immagini. Il confronto di due dump (prima e dopo uno scenario) mostrerà quali oggetti non sono stati liberati. Se il numero di oggetti Activity è aumentato ma la schermata è stata chiusa, si tratta di una perdita.
In Android Studio, aprire il dump tramite Memory Profiler: ordinare gli oggetti per Retained Size (più è grande, più memoria l'oggetto trattiene). Cercare istanze di Activity, Fragment e Bitmap che non dovrebbero esistere in memoria. Se tale oggetto esiste, andare al Reference Tree per vedere cosa lo sta trattenendo.
Profiling di rete traccia tutte le richieste HTTP dell'applicazione: URL, dimensione della risposta, tempo di esecuzione, codici di risposta e intestazioni. L'obiettivo principale è trovare richieste che impiegano troppo tempo, trasferiscono dati eccessivi o vengono effettuate inutilmente.
Su Android, il Network Profiler mostra una sequenza temporale di tutte le chiamate di rete, la loro durata e la quantità di dati trasferiti. Ogni richiesta può essere aperta per visualizzare le intestazioni complete e il corpo della risposta. Su iOS, Instruments Network per attività simili utilizza il monitoraggio del sistema di caricamento URL e mostra un diagramma a cascata delle richieste.
Problemi tipici identificati dal profiling di rete: mancanza di caching (lo stesso JSON viene caricato ogni volta che si apre una schermata), richieste duplicate (più componenti richiedono contemporaneamente gli stessi dati), risposte grandi (il server invia 5 MB di JSON quando sono necessari 100 KB). Per ogni problema esiste una soluzione standard: configurare la cache tramite OkHttp o URLSession, combinare le sottoscrizioni tramite Combine o Flow, aggiungere la paginazione lato server.
Prestare particolare attenzione al tempo al primo byte (TTFB). Se il TTFB supera 500 ms su una buona connessione, il problema è lato server. Se la richiesta in sé è veloce ma l'analisi del JSON richiede secondi, il problema è nella deserializzazione e deve essere profilato separatamente.
Profiling energetico misura come un'applicazione influisce sulla durata della batteria. Questo è un tipo di profiling relativamente nuovo ma criticamente importante per le applicazioni mobili — gli utenti eliminano le app che scaricano eccessivamente la batteria. Energy Profiler in Android Studio e Energy Log in Instruments mostrano quali operazioni (Wi-Fi, GPS, CPU, Bluetooth) consumano energia in ogni momento.
Principali consumatori di energia nelle applicazioni mobili: WakeLock (mantenere il processore attivo), GPS Location (aggiornamenti costanti della posizione), richieste di rete (specialmente su reti 4G/5G), animazioni in background. Energy Profiler sovrappone gli eventi dell'applicazione su una scala di consumo energetico — se c'è un picco nel grafico, è possibile identificare con precisione quale operazione lo ha causato.
Secondo Apple WWDC 2023, ridurre il consumo energetico di un'applicazione del 20% aumenta la fidelizzazione degli utenti del 12%, poiché gli utenti tendono a eliminare le app che scaricano molto la batteria. La raccomandazione è di abilitare sempre Energy Profiler quando si testano scenari con GPS, sincronizzazione in background e streaming.
La scelta dello strumento dipende dalla piattaforma e dal tipo di profiling. Per Android, il set principale è Android Studio Profiler (CPU, Memoria, Rete, Energia), LeakCanary (perdite di memoria) e Perfetto (profiling a livello di sistema). Per iOS — Xcode Instruments con i modelli: Time Profiler, Allocations, Leaks, Energy Log, Network e Core Animation.
Per lo sviluppo multipiattaforma con Flutter, utilizzare DevTools con i moduli Timeline (CPU), Memory, Network e Debugger. Per React Native — React DevTools e Flipper di Facebook, che supporta l'ispezione di rete, database e gerarchia dell'interfaccia. Indipendentemente dal framework, i principi di base del profiling sono universali: misurare prima e dopo l'ottimizzazione, registrare una baseline, confrontare le metriche a ogni modifica del codice.
Gli approcci moderni includono il profiling automatizzato in CI. Su Android, Firebase Test Lab supporta le misurazioni delle prestazioni insieme ai test dell'interfaccia: si ottengono non solo risultati di superamento/fallimento ma anche grafici di CPU, Memoria e Rete per ogni iterazione. Funzionalità simili per iOS sono fornite da GitHub Actions con XCUITest e Instruments CLI.
Per un controllo rapido di una singola metrica, utilizzare il profiler integrato dell'IDE. Per un'analisi completa delle perdite — strumenti specializzati (LeakCanary, Instruments Leaks). Per il profiling a livello di sistema dei driver — Perfetto (Android) o DTrace (macOS). La combinazione di due o tre strumenti copre il 95% degli scenari di profiling.
Domande Frequenti
Logging mostra una sequenza di eventi in forma testuale, mentre il profiling fornisce metriche quantitative — quanto tempo, memoria, CPU e rete consuma ogni frammento di codice. Il profiling risponde alla domanda “quanto”, mentre il logging risponde a “cosa è successo”.
Si consiglia di profilare prima di ogni rilascio importante, quando si introducono nuovi componenti pesanti dell'interfaccia e quando sorgono reclami sulle prestazioni. Idealmente, il profiling è integrato nel CI e viene eseguito automaticamente a ogni pull request.
Sì, ed è addirittura preferibile rispetto all'uso di un emulatore. Un dispositivo reale mostra le prestazioni effettive considerando i limiti dell'hardware specifico. Android Studio Profiler e Xcode Instruments supportano il profiling su un dispositivo connesso senza alcuna restrizione.
Sì, qualsiasi profiler aggiunge overhead. Per il profiling della CPU basato su campionamento, l'overhead è dell'1–5%. Per il profiling della memoria con dump dell'heap, è fino al 10% al momento del dump. Gli strumenti moderni cercano di minimizzare l'impatto, ma deve sempre essere considerato nell'interpretazione dei risultati.
Baseline è un insieme di metriche di prestazioni di riferimento acquisite sulla prima versione stabile dell'applicazione. A ogni modifica del codice, confrontare le nuove metriche con la baseline. Se il tempo di avvio è aumentato di 50 ms rispetto alla baseline, indagare sulla causa prima di unire le modifiche.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche