2013-04-10 14 views
9

Ho avuto un incidente exc_bad_access piuttosto interessante oggi. Dopo un sacco di scavo, ho trovato le seguenti informazioni (in esecuzione in simulatore):In che modo NSLogs può causare l'arresto anomalo del codice?

Se ho appena eseguito il codice, l'app si arresterebbe in modo casuale a un punto casuale durante il caricamento dei dati nel mio oggetto gestito. Da quello che ho potuto vedere, si è verificato un arresto anomalo quando ho caricato i dati nell'oggetto gestito, non nelle sezioni che sono state convertite da JSON per dati sull'oggetto effettivamente utilizzato (da stringhe e NSNull a ints/float e nils)

I crash casuali sono, ovviamente, malvagi, quindi ho provato a passare attraverso il processo nel debugger, ma ciò non è risultato pratico - stavo elaborando un sacco di oggetti, quindi li ho passati uno dopo l'altro semplicemente non ha funzionato Così ho deciso di aggiungere alcuni NSLogs per tracciare il processo e cercare di individuare un pattern in questo modo.

Immediatamente risolto l'incidente.

Solo un NSLog, in qualsiasi punto del processo, ha impedito l'arresto.

Alla fine ho rintracciato la traccia dello stack e ho trovato il problema: stavo accedendo all'oggetto gestito in un ambiente con thread, ma NON dall'interno del metodo performBlockAndWait: MOC associato. A quel punto, l'incidente è stato incredibilmente ovvio per me - sono scioccato di non avere più problemi prima. Sono disposto a scommettere che tra avere un piccolo insieme di dati di test di 2-3 oggetti e avere il codice di debug lì con NSlog, l'errore è stato mascherato in modo abbastanza efficace in precedenza ... ma la domanda rimane:

Perché un NSLog impedisce l'arresto anomalo dell'app? Come diavolo potrebbe un pezzo di codice senza effetti collaterali modificare l'esecuzione del resto dell'app? Questo non ha senso!

+0

usi ovunque performSelector: metodo e selettore che non restituisce il tipo id come parametro per esso? Alcune volte NSLog può prevenire errori che si sono verificati con questi errori.In tal caso è necessario utilizzare NSInvocation – BergP

risposta

12

Sorprendentemente, questa è una situazione abbastanza comune: l'ho vista più di una volta quando abilitare la registrazione in un luogo apparentemente non correlato avrebbe immediatamente risolto un problema di temporizzazione da qualche altra parte.

La ragione di ciò è che NSLog, come molte altre funzioni di uscita, ha la sincronizzazione interna. C'è un mutex da qualche parte che protegge l'accesso ai buffer interni di NSLog, nello stesso NSLog o in una delle librerie di I/O che utilizza. Questa sincronizzazione consente ai chiamanti di utilizzare NSLog da più thread. È questa sincronizzazione che modifica i tempi del tuo programma, influendo su una condizione di gara e alla fine risolvendo un crash.

+0

Non lo sapevo. Bello uno, +1, solo wow. –

+0

Non ho mai nemmeno pensato a questa possibilità, ma immagino che ciò possa causare enormi cambiamenti nel modo in cui il mio codice gira. Cool – RonLugge

+1

@RonLugge Il nostro intero team è rimasto sbalordito quando abbiamo fatto questa scoperta per la prima volta: abbiamo ricevuto segnalazioni di frequenti arresti casuali da uno dei nostri siti installati, abbiamo chiesto loro di trasformare i livelli di registro da "errore" a "debug" "e mandaci i log. Quando sono tornati da noi con la risposta che una volta che hanno attivato i livelli di log non possono più riprodurre il crash, non li abbiamo creduti all'inizio, ma una volta che abbiamo disattivato il log era sempre "attivo" nello sviluppo), abbiamo riprodotto il crash da soli :) – dasblinkenlight

3

Perché un NSLog impedisce l'arresto anomalo dell'app? Come mai una porzione di codice senza effetti collaterali modifica l'esecuzione del resto di l'app? Questo non ha senso!

In effetti questo ha un senso. Veramente.

Un singolo NSLog costringe a stampare qualcosa sulla tua console, ci vuole qualche frazione di secondo e tra l'elaborazione su somethread è finito e il crash (potrebbe essere dovuto alla non disponibilità di input è) non più.

L'errore potrebbe essere dovuto alla chiamata asincrona. Il tuo prossimo processo inizia prima di finire quello precedente. E il tuo prossimo processo necessita di dati dal processo precedente. NSLog consuma un po 'di tempo.

+0

Mentre ci pensavo, non aveva senso per me in questo contesto - mentre potrei trovarmi in un ambiente multithread, solo una "copia" di questo codice sarebbe in esecuzione in qualsiasi data tempo (quindi avrei "thread principale" e "thread dati"). Qualunque sia la causa per cui gli oggetti gestiti non sono sicuri, non dovrebbe essere effettuato da un NSLog ... ho pensato. – RonLugge

+0

Io li guardo abbastanza regolarmente :( –

Problemi correlati