iOS
Profilo con strumenti
Ricerca…
introduzione
Xcode include un'applicazione di ottimizzazione delle prestazioni denominata Instruments che è possibile utilizzare per profilare l'applicazione utilizzando tutti i tipi di metriche differenti. Hanno strumenti per controllare l'utilizzo della CPU, l'utilizzo della memoria, le perdite, l'attività di file / rete e l'utilizzo di energia, solo per citarne alcuni. È davvero facile iniziare a profilare la tua app da Xcode, ma a volte non è così facile capire cosa vedi quando si tratta di una profilazione, il che dissuade alcuni sviluppatori dall'essere in grado di utilizzare questo strumento al massimo potenziale.
Time Profiler
Il primo strumento che vedrai è il Time Profiler
. A intervalli misurati, Instruments interromperà l'esecuzione del programma e prenderà una traccia di stack su ogni thread in esecuzione. Pensa a ciò premendo il pulsante di pausa nel debugger di Xcode. Ecco un'anteprima del Time Profiler: -
Questa schermata visualizza l' Call Tree
. L' Call Tree
mostra la quantità di tempo trascorso nell'esecuzione in vari metodi all'interno di un'app. Ogni riga è un metodo diverso seguito dal percorso di esecuzione del programma. Il tempo trascorso in ciascun metodo può essere determinato dal numero di volte in cui il profiler viene fermato in ogni metodo. Ad esempio, se vengono eseguiti 100 campioni ad intervalli di 1 millisecondo e si trova un particolare metodo in cima allo stack in 10 campioni, è possibile dedurre che è stato impiegato circa il 10% del tempo di esecuzione totale - 10 millisecondi in quel metodo. È un'approssimazione abbastanza approssimativa, ma funziona!
Dalla barra dei menu Xcode's
, selezionare Product\Profile
, o press ⌘I
. Questo costruirà l'app e avvierà gli strumenti. Sarai accolto con una finestra di selezione simile a questa:
Questi sono tutti modelli diversi forniti con gli strumenti.
Seleziona lo strumento Time Profiler
e fai clic su Scegli. Questo aprirà un nuovo documento di strumenti. Fai clic sul pulsante rosso di registrazione in alto a sinistra per avviare la registrazione e avviare l'app. È possibile che venga chiesta la password per autorizzare gli strumenti ad analizzare altri processi: non temere, è sicuro fornire qui! Nella finestra degli strumenti , puoi vedere il tempo che conta e una piccola freccia muoversi da sinistra a destra sopra il grafico al centro dello schermo. Questo indica che l'app è in esecuzione.
Ora inizia a utilizzare l'app. Cerca alcune immagini e visualizza in dettaglio uno o più risultati di ricerca. Probabilmente hai notato che entrare in un risultato di ricerca è noiosamente lento e scorrere un elenco di risultati di ricerca è anche incredibilmente fastidioso - è un'app terribilmente goffo!
Bene, sei fortunato, perché stai per iniziare a risolverlo! Tuttavia, per prima cosa inizierai a fare un giro veloce su ciò che stai guardando in Strumenti . Innanzitutto, assicurati che il selettore di visualizzazione sul lato destro della barra degli strumenti abbia entrambe le opzioni selezionate, in questo modo:
Ciò garantirà che tutti i pannelli siano aperti. Ora studia lo screenshot qui sotto e la spiegazione di ogni sezione sottostante:
1. Questi sono i controlli di registrazione . Il pulsante rosso "registra" arresta e avvia l'applicazione che viene attualmente profilata quando viene cliccata (si passa da un'icona di registrazione a un'icona di arresto). Il pulsante di pausa fa esattamente ciò che ti aspetti e sospende l'esecuzione corrente dell'app.
2. Questo è il timer di esecuzione. Il timer conta per quanto tempo è stata eseguita l'applicazione che è stata profilata e quante volte è stata eseguita. Se si interrompe e quindi si riavvia l'app utilizzando i controlli di registrazione, si avvierà una nuova corsa e il display mostrerà Esegui 2 di 2.
3. Questo è chiamato una traccia. Nel caso del template di Time Profiler che hai selezionato, c'è solo uno strumento quindi c'è solo una traccia. Imparerai di più sulle specifiche del grafico mostrato qui più avanti nel tutorial.
4. Questo è il pannello dei dettagli. Mostra le principali informazioni sul particolare strumento che stai utilizzando. In questo caso, mostra i metodi più "caldi", cioè quelli che hanno consumato più tempo della CPU. Se fai clic sulla barra nella parte superiore che indica Albero delle chiamate (quella a sinistra) e seleziona Elenco di campioni, ti verrà presentata una diversa visualizzazione dei dati. Questa vista mostra ogni singolo campione. Fai clic su alcuni campioni e vedrai la traccia dello stack catturata apparire nella finestra di ispezione Dettagli estesi.
5. Questo è il pannello degli ispettori. Esistono tre ispettori: Impostazioni di registrazione, Impostazioni di visualizzazione e Dettagli estesi. A breve imparerai di più su alcune di queste opzioni.
Drilling Deep
Esegui una ricerca di immagini e approfondisci i risultati. Personalmente mi piace cercare "cane", ma scegliere quello che desideri - potresti essere uno di quei gatti!
Ora, scorrere verso l'alto e verso il basso nell'elenco alcune volte in modo da avere una buona quantità di dati nel Time Profiler
. Dovresti notare i numeri al centro dello schermo che cambiano e il grafico che si riempie; questo ti dice che i cicli della CPU sono in uso.
Davvero non ti aspetteresti che un'interfaccia utente sia così goffa come questa table view
non è pronta per essere spedita fino a quando non scorre come un burro! Per aiutare a individuare il problema, è necessario impostare alcune opzioni.
Sul lato destro, seleziona l' ispettore Impostazioni schermo (or press ⌘+2)
. Nell'ispettore , sotto la sezione Call Tree
, selezionare Separa per thread , Inverti Call Tree
, Nascondi simboli mancanti e Nascondi librerie di sistema. Sembrerà così:
Ecco cosa sta facendo ciascuna opzione per i dati visualizzati nella tabella a sinistra:
Separato per thread: ogni thread deve essere considerato separatamente. Ciò consente di capire quali thread sono responsabili della maggior quantità di utilizzo della CPU .
Inverti albero delle chiamate: con questa opzione, la stack trace
dello stack trace
viene considerata dall'alto verso il basso. Questo di solito è quello che vuoi, perché vuoi vedere i metodi più profondi in cui la CPU sta spendendo il suo tempo.
Nascondi simboli mancanti: se non è possibile trovare il file dSYM
per la tua app o un system framework
, invece di vedere i nomi dei metodi (simboli) nella tabella, vedrai solo i valori esadecimali corrispondenti agli indirizzi all'interno del binario. Se questa opzione è selezionata, vengono visualizzati solo i simboli completamente risolti ei valori esadecimali non risolti sono nascosti. Questo aiuta a declassare i dati presentati.
Nascondi librerie di sistema: quando questa opzione è selezionata, vengono visualizzati solo i simboli della tua app. È spesso utile selezionare questa opzione, poiché di solito ti interessa solo dove la CPU trascorre del tempo nel tuo codice - non puoi fare molto su quanta CPU le system libraries
stanno usando!
Flatten ricorsione: questa opzione tratta le funzioni ricorsive (quelle che si chiamano) come una voce in ogni stack trace
, piuttosto che multiple.
Funzioni principali: Abilitando questa opzione, gli Instruments
considerano il tempo totale trascorso in una funzione come la somma del tempo direttamente all'interno di tale funzione, nonché il tempo trascorso nelle funzioni chiamate da tale funzione.
Quindi se la funzione A chiama B, allora il tempo di A viene indicato come il tempo trascorso in A PLUS il tempo trascorso in B. Questo può essere davvero utile, in quanto ti consente di scegliere la cifra più grande ogni volta che scendi nello stack di chiamate, azzerando in sui metodi più dispendiosi in termini di tempo.
Se stai eseguendo un'app Objective-C
, c'è anche un'opzione di Show Obj-C Only : se questa è selezionata, vengono visualizzati solo i metodi Objective-C
, piuttosto che le funzioni C
o C++
. Non ce ne sono nel tuo programma, ma se stai guardando un'app OpenGL
, potrebbe avere un C++
, per esempio.
Sebbene alcuni valori potrebbero essere leggermente diversi, l'ordine delle voci dovrebbe essere simile alla tabella seguente una volta abilitate le opzioni sopra riportate:
Beh, questo sicuramente non sembra troppo bello. La maggior parte del tempo viene impiegata nel metodo che applica il filtro "tonale" alle foto in miniatura. Ciò non dovrebbe rappresentare uno shock per te, dato che il caricamento e lo scorrimento della tabella erano le parti più crudeli dell'interfaccia utente, e questo è il momento in cui le celle della tabella vengono costantemente aggiornate.
Per saperne di più su cosa sta succedendo all'interno di quel metodo, fai doppio clic sulla sua riga nella tabella. In questo modo verrà visualizzata la seguente visualizzazione:
Beh, questo è interessante, no? applyTonalFilter()
è un metodo aggiunto a UIImage
in un'estensione e quasi il 100 % del tempo trascorso in esso viene impiegato per creare l'output di CGImage dopo aver applicato il filtro di immagine.
Non c'è molto che si possa fare per accelerare questo processo: la creazione dell'immagine è un processo piuttosto intenso e richiede tutto il tempo necessario. Proviamo a fare un passo indietro e vediamo da dove viene chiamato applyTonalFilter()
. Fai clic su Call Tree
nella traccia di breadcrumb nella parte superiore della visualizzazione del codice per tornare alla schermata precedente:
Ora fai clic sulla piccola freccia a sinistra della riga applyTonalFilter nella parte superiore della tabella. Questo spiegherà l'albero delle chiamate per mostrare il chiamante di applyTonalFilter. Potrebbe essere necessario aprire anche la riga successiva; quando si esegue il profiling di Swift, a volte ci saranno delle righe duplicate nell'albero delle chiamate, precedute da @objc. Ti interessa la prima riga preceduta dal nome di destinazione della tua app (InstrumentsTutorial):
In questo caso, questa riga fa riferimento alla cellForItemAtIndexPath
raccolta dei risultati cellForItemAtIndexPath
. Fare doppio clic sulla riga per vedere il codice associato dal progetto.
Ora puoi vedere qual è il problema. Il metodo per applicare il filtro tonale richiede molto tempo per essere eseguito e viene chiamato direttamente da cellForItemAtIndexPath, che bloccherà il main thread
(e quindi l'intera interfaccia utente) ogni volta che viene richiesta un'immagine filtrata.
Accantonamenti
Vi sono informazioni dettagliate su tutti gli oggetti che vengono creati e sulla memoria che li supporta; mostra anche retain counts
di ciascun oggetto. Per iniziare da capo con un nuovo instruments profile
, esci dall'app Strumenti. Questa volta, crea ed esegui l'app e apri Debug Navigator nell'area Navigatori. Quindi fare clic su Memoria per visualizzare i grafici di utilizzo della memoria nella finestra principale:
Questi grafici sono utili per avere una rapida idea di come sta andando la tua app. Ma avrai bisogno di un po 'più di energia. Fare clic sul pulsante Profile in Instruments
e quindi su Trasferisci per portare questa sessione in Strumenti . Lo strumento Allocations si avvierà automaticamente.
Questa volta noterai due tracce. Uno è chiamato allocazioni e uno è chiamato perdite. La traccia delle allocazioni verrà discussa in dettaglio più avanti; la traccia di Leaks è generalmente più utile in Objective-C e non verrà trattata in questo tutorial. Quindi quale bug hai intenzione di rintracciare dopo? C'è qualcosa di nascosto nel progetto che probabilmente non sai è lì. Probabilmente hai sentito delle perdite di memoria. Ma quello che potresti non sapere è che in realtà ci sono due tipi di perdite:
Le vere perdite di memoria sono quelle in cui un oggetto non viene più referenziato da nulla ma ancora assegnato - ciò significa che la memoria non può mai essere riutilizzata. Anche con Swift e ARC
aiutano a gestire la memoria, il tipo più comune di perdita di memoria è un retain cycle or strong reference cycle
un retain cycle or strong reference cycle
. Questo è quando due oggetti contengono forti riferimenti l'uno all'altro, così che ogni oggetto mantiene l'altro da essere deallocato. Ciò significa che la loro memoria non viene mai rilasciata!
La crescita illimitata della memoria è dove la memoria continua ad essere allocata e non è mai data la possibilità di essere deallocati . Se continua così per sempre, allora ad un certo punto la system's memory
sarà piena e avrai un grosso problema di memoria nelle tue mani. In iOS questo significa che l'app verrà uccisa dal sistema.
Con lo strumento Allocations in esecuzione sull'app, effettua cinque diverse ricerche nell'app ma non approfondisci ancora i risultati. Assicurati che le ricerche abbiano dei risultati! Ora lascia che l'app si stabilizzi un attimo aspettando qualche secondo.
Avresti dovuto notare che il grafico nella traccia delle allocazioni è in aumento. Questo ti sta dicendo che la memoria è stata assegnata. È questa funzione che ti guiderà a trovare una unbounded memory growth
.
Quello che stai per eseguire è generation analysis
. Per fare ciò, premi il pulsante chiamato Mark Generation. Troverai il pulsante nella parte superiore della finestra Impostazioni schermo:
Premerlo e vedrai apparire una bandiera rossa nella traccia, in questo modo:
Lo scopo generation analysis
di generation analysis
è eseguire un'azione più volte e vedere se la memoria sta crescendo in unbounded fashion
. Esegui una ricerca, attendi qualche secondo per caricare le immagini, quindi torna alla pagina principale. Quindi segna di nuovo la generazione. Fallo ripetutamente per ricerche diverse. Dopo una trivellazione in alcune ricerche, gli strumenti saranno simili a questo:
A questo punto, dovresti diventare sospettoso. Si noti come il grafico blu sta salendo con ogni ricerca in cui si fora . Beh, non è certamente buono. Ma aspetta, per quanto riguarda gli memory warnings?
sulla memory warnings?
Sai di quelli, giusto? Memory warnings
sono il modo di iOS di dire a un'app che le cose si stanno facendo più strette nel reparto di memoria e che è necessario cancellare un po 'di memoria.
È possibile che questa crescita non sia solo dovuta alla tua app; potrebbe essere qualcosa nelle profondità di UIKit
che sta trattenendo la memoria. Dai al framework di sistema e alla tua app la possibilità di svuotare la memoria prima di puntare il dito su uno dei due.
Simula un memory warning
selezionando Instrument\Simulate Memory Warning
nella barra dei menu di Instruments o Hardware\Simulate Memory Warning
dalla barra dei menu simulator's
. Noterai che l'utilizzo della memoria diminuisce leggermente, o forse non del tutto. Certamente non si torna a dove dovrebbe essere. Quindi c'è ancora una crescita di memoria illimitata da qualche parte.
La ragione per contrassegnare una generazione dopo ogni iterazione di perforazione in una ricerca è che è possibile vedere quale memoria è stata allocata tra ogni generazione. Dai un'occhiata nel pannello dei dettagli e vedrai un paio di generazioni.