30

Ho un'app per iOS scritta in Swift che sta perdendo memoria - in alcune situazioni alcuni oggetti dovrebbero essere rilasciati ma non lo sono. Ho imparato a conoscere il problema con la semplice aggiunta deinit messaggi di debug in questo modo:Come eseguire il debug delle perdite di memoria quando lo strumento Leaks non le mostra?

deinit { 
    println("DEINIT: KeysProvider released") 
} 

Quindi, il messaggio deinit dovrebbe essere presente nella console dopo tali eventi che dovrebbe causare l'oggetto da rilasciare. Tuttavia, per alcuni degli oggetti che dovrebbero essere rilasciati, manca il messaggio. Ancora, Leaks Developer Tool non mostra alcuna perdita. Come risolvo tale situazione?

+0

non sono sicuro questo è un buon test. Ci può essere da qualche parte nel codice che sta ancora tenendo un puntatore a quelle routine. Oppure il compilatore Swift è abbastanza intelligente da non chiamare 'deinit' se non è necessario. Hai bisogno di un test migliore per la perdita di memoria. – zaph

risposta

63

In Xcode 8, è possibile fare clic sul pulsante "Debug Memory Graph", debugmemorygraphbutton nella barra degli strumenti di debug (visualizzata nella parte inferiore dello schermo):

debug memory graph

Proprio identifica l'oggetto nel pannello di sinistra che ritieni debba essere stato deallocato e ti mostrerà il grafico dell'oggetto (mostrato nella tela principale, sopra). Questo è molto utile per identificare rapidamente dove sono stati stabiliti i riferimenti forti sull'oggetto in questione. Da qui, puoi iniziare la tua ricerca, diagnosticare perché quei forti riferimenti non sono stati risolti (ad esempio se l'oggetto in questione ha un forte riferimento da qualcos'altro che avrebbe dovuto essere deallocato, guarda anche il grafico di quell'oggetto, e potresti trovare il problema (ad es. cicli di riferimento forti, timer ripetuti, ecc.)

Si noti che nel pannello di destra viene visualizzato l'albero delle chiamate.Ho ottenuto che, attivando l'opzione "malloc stack" logging nelle impostazioni dello schema:

malloc stack

In ogni caso, dopo aver fatto questo, si può quindi fare clic sulla freccia accanto alla chiamata di metodo indicata nella pila traccia nel pannello di destra della prima fotografia istantanea dello schermo al di sopra, e si può vedere dove quel forte richiamo è stato originariamente creato:

code

la tecnica diagnostica di memoria sopra (e non solo) è dimostrato nella seconda parte del WWDC 2016 Visual Debugging with Xcode.


La tecnica strumenti tradizionali (particolarmente utile se si utilizza le vecchie versioni di Xcode) è descritto di seguito, nella mia risposta originale.


Io suggerirei di usare strumenti funzione 'allocazioni' con il 'Record di riferimento conta' caratteristica:

record reference counts

È possibile eseguire l'applicazione in strumenti e poi cercare il tuo classe che si sa è fuoriuscito e drill facendo clic sulla freccia:

enter image description here

È quindi possibile forare i dettagli e guardare la traccia dello stack mediante il pannello "Esteso Dettagli" a destra:

extended details

In questo pannello "Esteso Dettagli", si concentrano sul vostro codice in nero piuttosto che il sistema chiama in grigio. In ogni caso, dal pannello "esteso Dettagli", è possibile quindi praticare nel codice sorgente, proprio nel Instruments ::

your code

Per ulteriori informazioni e manifestazioni in utilizzando strumenti di rintracciare problemi di memoria, fare riferimento alla :

+0

Grazie. La procedura che hai suggerito è probabilmente il miglior uso di strumenti per rilevare cicli forti. Tuttavia, questo non è ancora molto utile. Riesco a vedere quale è il numero di riferimento per la classe delle particelle in questo momento, ma quello di cui avrei davvero bisogno è quello che gli oggetti contengono quei riferimenti ... Ma questo è un cattivo design degli strumenti, la tua risposta è ottima. Grazie! – drasto

+0

Non solo mostra ciò che è il conteggio dei riferimenti, ma, soprattutto, ti mostra dove questi riferimenti forti sono stati stabiliti. Ho usato un ciclo di riferimento forte come esempio, ma funziona con qualsiasi scenario di proprietà. – Rob

+0

Sì, ma mi mostra dove ** tutti ** i riferimenti forti sono stati stabiliti attraverso la cronologia dell'oggetto. Questo è quasi inutile dato il flusso del programma tipico in cui molti riferimenti vengono mantenuti e rilasciati.Mi interessano solo i forti riferimenti inediti e ottengo solo il loro conteggio: quanti di loro ci sono al momento (numero nella colonna RefCt nell'ultima riga). Tutti quelli conservati e poi rilasciati i riferimenti sono solo lo spamming sul tavolo per me. Troppe informazioni senza la possibilità di trovare quelle parti di cui ho veramente bisogno sono solitamente le stesse di nessuna informazione. – drasto

2

Utilizzare gli strumenti per verificare la presenza di perdite e perdite di memoria dovute alla memoria conservata ma non trapelata. Quest'ultimo è memoria inutilizzata che è ancora indicata. Usa Mark Generation (Heapshot) nello strumento Allocations on Instruments.

In HowTo Heapshot trovare memoria insinuano sin, vedi: bbum blog

Fondamentalmente il metodo è quello di eseguire Instruments allocare utensile, prendere un heapshot, eseguire un'iterazione del codice e prendere un'altra heapshot ripetere 3 o 4 volte. Ciò indicherà la memoria allocata e non rilasciata durante le iterazioni.

Per calcolare i risultati, vedere le singole allocazioni.

Se avete bisogno di vedere dove conserva, stampa e autoreleases si verificano per uno strumenti uso oggetto:

Run in strumenti, in dotazioni fissate "conta di riferimento di registrazione" a (per Xcode 5 e abbassare dovete interrompere la registrazione per impostare l'opzione). Causa l'esecuzione dell'applicazione, interrompi la registrazione, esegui il drill down e sarai in grado di vedere dove si sono verificati tutti i ritardi, i rilasci e le autoresitazioni.