Segnale EXC_BAD_ACCESS ricevuto


290

Quando si distribuisce l'applicazione sul dispositivo, il programma si chiuderà dopo alcuni cicli con il seguente errore:

Program received signal: "EXC_BAD_ACCESS".

Il programma funziona senza problemi sul simulatore di iPhone, inoltre eseguirà il debug e funzionerà finché eseguirò le istruzioni una alla volta. Non appena lo lascio correre di nuovo, colpirò il EXC_BAD_ACCESSsegnale.

In questo caso particolare, si è verificato un errore nel codice dell'accelerometro. Non verrebbe eseguito all'interno del simulatore, motivo per cui non ha generato errori. Tuttavia, verrebbe eseguito una volta distribuito sul dispositivo.

La maggior parte delle risposte a questa domanda riguarda l' EXC_BAD_ACCESSerrore generale , quindi lo lascerò aperto come un errore generale per il temuto errore di accesso errato.

EXC_BAD_ACCESSviene in genere generato come risultato di un accesso alla memoria illegale. Puoi trovare ulteriori informazioni nelle risposte di seguito.

Hai già riscontrato il EXC_BAD_ACCESSsegnale in precedenza e come lo hai gestito?

Risposte:


196

Dalla tua descrizione sospetto che la spiegazione più probabile sia che tu abbia qualche errore nella gestione della memoria. Hai detto che hai lavorato sullo sviluppo di iPhone per alcune settimane, ma non se hai esperienza con l'obiettivo C in generale. Se provieni da un altro background, potrebbe essere necessario un po 'di tempo prima di interiorizzare veramente le regole di gestione della memoria, a meno che tu non ne faccia un punto importante.

Ricorda, qualsiasi cosa tu ottenga da una funzione di allocazione (di solito il metodo di allocazione statica, ma ce ne sono alcuni altri), o un metodo di copia, possiedi anche la memoria e devi rilasciarla quando hai finito.

Ma se ricevi qualcosa da qualsiasi altra cosa, inclusi i metodi di fabbrica (ad esempio [NSString stringWithFormat]), avrai un riferimento di rilascio automatico, il che significa che potrebbe essere rilasciato in futuro in un altro codice - quindi è fondamentale che se ne hai bisogno per mantenerlo al di là della funzione immediata che lo conservi. In caso contrario, la memoria potrebbe rimanere allocata durante l'utilizzo o essere rilasciata ma, per coincidenza, ancora valida, durante il test dell'emulatore, ma è più probabile che venga rilasciata e mostrata come errore di accesso errato durante l'esecuzione sul dispositivo.

Il modo migliore per rintracciare queste cose, e comunque una buona idea (anche se non ci sono problemi apparenti) è eseguire l'app nello strumento Strumenti, specialmente con l'opzione Perdite.


2
Avevo un codice di campionamento dell'accelerometro che non era vitale per la mia app, che dopo la rimozione ha eliminato l'errore di accesso errato. Il che ha senso considerando che il simulatore non ha un accelerometro. Trovo strano che questo codice sia esistito, intatto, per una settimana prima di causare questo errore ...
Héctor Ramos,

Sono nuovo di Objective-C, quindi la maggior parte dei miei problemi dovrebbe derivare dalla gestione della memoria. Dopo alcuni anni in C ++, ho usato principalmente Java negli ultimi tre o quattro anni, quindi sono diventato arrugginito nella gestione della memoria. Grazie per la tua risposta!
Héctor Ramos,

4
Nessun problema - felice di averlo risolto. La gestione della memoria non è davvero difficile da affrontare: devi solo assicurarti di imparare le regole e entrare in buone abitudini.
philsquared del

Il problema che ho avuto sembra essere esclusivamente quello di essere troppo aggressivo nel rilasciare stringhe (e simili) che creo. Non sono ancora sicuro al 100% su cosa dovrebbe essere rilasciato e quando, ma la risposta di Phil sicuramente ha aiutato.
pluckyglen,

Se l'ho seguito correttamente, cmculloh, sì, era la cosa giusta da fare. Non si possiede l'oggetto return da objectAtIndex.
philsquared,

101

Una delle principali cause di EXC_BAD_ACCESS è il tentativo di accedere agli oggetti rilasciati.

Per scoprire come risolvere questo problema, leggi questo documento: DebuggingAutoReleasePool

Anche se non pensi di "rilasciare oggetti rilasciati automaticamente", questo si applica a te.

Questo metodo funziona molto bene. Lo uso sempre con grande successo !!

In breve, questo spiega come utilizzare la classe di debug NSZombie di Cocoa e lo strumento "malloc_history" della riga di comando per trovare esattamente a quale oggetto rilasciato è stato effettuato l'accesso nel codice.

Nota a margine:

L'esecuzione degli strumenti e il controllo delle perdite non aiuta a risolvere EXC_BAD_ACCESS. Sono abbastanza sicuro che le perdite di memoria non abbiano nulla a che fare con EXC_BAD_ACCESS. La definizione di perdita è un oggetto a cui non si ha più accesso e pertanto non è possibile chiamarlo.

AGGIORNAMENTO: ora utilizzo Instruments per eseguire il debug delle perdite. Da Xcode 4.2, scegli Prodotto-> Profilo e quando Strumenti viene avviato, scegli "Zombi".


18
Quel sidenote è molto importante. Le perdite non possono causare EXC_BAD_ACCESS (hanno altri problemi). Ho scritto questo per cercare di chiarire idee sbagliate su EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco,

4
Lo strumento zombi in Xcode è geniale! Ho trovato il colpevole in 3 minuti non ore.
Aram Kocharyan

1
link sopra in risposta in non disponibile. Mostra 404 errore non trovato.
Tejas,

12

Un segnale EXC_BAD_ACCESS è il risultato del passaggio di un puntatore non valido a una chiamata di sistema. Ne ho ricevuto uno poco prima con un programma di test su OS X: stavo passando una variabile non inizializzata a pthread_join()causa di un errore di battitura precedente.

Non ho familiarità con lo sviluppo di iPhone, ma dovresti ricontrollare tutti i puntatori del buffer che stai passando alle chiamate di sistema. Aumenta completamente il livello di avviso del compilatore (con gcc, usa le opzioni -Walle -Wextra). Abilitare il maggior numero possibile di diagnostica sul simulatore / debugger.


8

Nella mia esperienza, ciò è generalmente causato da un accesso alla memoria illegale. Controllare tutti i puntatori, in particolare i puntatori a oggetti, per assicurarsi che siano inizializzati. Assicurati che il tuo file MainWindow.xib, se ne usi uno, sia impostato correttamente, con tutte le connessioni necessarie.

Se nessuno di questi controlli su carta gira nulla e non accade quando si esegue il passaggio singolo, prova a individuare l'errore con le istruzioni NSLog (): cospargi il codice con loro, spostandoli finché non isola la linea che sta causando l'errore. Quindi impostare un punto di interruzione su quella linea ed eseguire il programma. Quando raggiungi il punto di interruzione, esamina tutte le variabili e gli oggetti in esse contenuti per vedere se qualcosa non sembra come ti aspetti, in particolare terrò d'occhio le variabili la cui classe di oggetti è qualcosa che non ti aspettavi. Se si suppone che una variabile contenga una UIWindow ma al suo interno abbia una NSNotification, lo stesso errore di codice sottostante potrebbe manifestarsi in modo diverso quando il debugger non è in funzione.


7

Ho appena trascorso un paio d'ore a rintracciare un EXC_BAD_ACCESS e ho scoperto che NSZombies e altri vars non sembravano dirmi nulla.

Per me, è stata una stupida affermazione NSLog con identificatori di formato, ma non sono passati argomenti.

NSLog(@"Some silly log message %@-%@");

Risolto da

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);

6

I video del WWDC 2010 sono disponibili per tutti i partecipanti al programma per sviluppatori Apple. C'è un ottimo video: "Sessione 311 - Analisi avanzata della memoria con strumenti" che mostra alcuni esempi dell'uso degli zombi negli strumenti e del debug di altri problemi di memoria.

Per un collegamento alla pagina di accesso, fai clic QUI .


6

Non una risposta completa, ma una situazione specifica in cui l'ho ricevuta è quando provo ad accedere a un oggetto "morto" perché ho provato a utilizzare il rilascio automatico:

netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];

Quindi, ad esempio, stavo effettivamente passando questo come oggetto per "notificare" (registrato come ascoltatore, osservatore, qualunque idioma ti piaccia) ma era già morto una volta inviata la notifica e avrei ricevuto EXC_BAD_ACCESS. Modificandolo [[MyNetObject alloc] init]e rilasciandolo in seguito, se del caso, risolto l'errore.

Un altro motivo per cui ciò può accadere è ad esempio se si passa un oggetto e si tenta di memorizzarlo:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Successivamente, quando si tenta di accedere a myObjectDefinedInHeader, è possibile che si verifichino problemi. usando:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

potrebbe essere quello di cui hai bisogno. Naturalmente questi sono solo un paio di esempi di ciò che ho incontrato e ci sono altri motivi, ma questi possono rivelarsi sfuggenti, quindi li menziono. In bocca al lupo!


5

Solo per aggiungere un'altra situazione in cui ciò può accadere:

Ho avuto il codice:

NSMutableString *string;
[string   appendWithFormat:@"foo"];

Ovviamente avevo dimenticato di allocare memoria per la stringa:

NSMutableString *string = [[NSMutableString alloc] init];
[string   appendWithFormat:@"foo"];

risolve il problema.


Questo non causa alcun errore per me perché la stringa viene inizializzata su zero e l'utilizzo del modello di oggetti null che chiama un metodo su zero non fa nulla.
Liron Yahdav,

5

Un altro metodo per rilevare le eccezioni EXC_BAD_ACCESS prima che si verifichino è l' analizzatore statico , in XCode 4+.

Esegui l'analizzatore statico con Prodotto> Analizza (maiusc + cmd + B). Facendo clic su tutti i messaggi generati dall'analizzatore si sovrapporrà un diagramma sull'origine che mostra la sequenza di ritiri / rilasci dell'oggetto offensivo.

inserisci qui la descrizione dell'immagine


5

Trovo utile impostare un breakpoint su objc_exception_throw. In questo modo il debugger dovrebbe interrompersi quando si ottiene EXC_BAD_ACCESS.

Le istruzioni sono disponibili qui Tecniche di debug


4

Usa la semplice regola di "se non l'hai allocata o conservata, non rilasciarla".


1
Espandi quella regola di "... copialo ..." e dovresti andare bene.
Fino al

4

Come eseguire il debug di EXC_BAD_ACCESS

Dai un'occhiata al link sopra e fai come dice .... Solo alcune brevi istruzioni per l'uso di NSZombies

Esegui l'applicazione e dopo che fallisce (dovrebbe essere visualizzato "Interrotto" anziché "EXC_BAD_ACCESS" ... controlla la Console (Esegui> Console) ... ora dovrebbe esserci un messaggio che dice a quale oggetto sta tentando di accedere.

-Ben


3

Ho eseguito il debug e il refactoring del codice per risolvere questo errore nelle ultime quattro ore. Un post sopra mi ha portato a vedere il problema:

Proprietà precedente: startPoint = [[DataPoint alloc] init]; startPoint = [DataPointList objectAtIndex: 0];
. . . x = startPoint.x - 10; // EXC_BAD_ACCESS

Proprietà dopo: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] retain];

Arrivederci EXC_BAD_ACCESS


Ho fatto un errore simile. Ho dimenticato di riavviare l'istanza che ha causato l'incidente e ho trascorso ore a capirlo. La tua esperienza mi ha illuminato per scoprire la mia. Grazie!
David.Chu.ca,

3

Spero che rilasci la 'stringa' quando hai finito!


3

Ho dimenticato di restituire me stesso in un metodo init ...;)


Questo dovrebbe essere un avviso / errore di tempo di compilazione e non un EXC_BAD_ACCESS durante il runtime.
stigi,

3

Questo è un filo eccellente. Ecco la mia esperienza: ho fatto un casino con la parola chiave keep / assegn su una dichiarazione di proprietà. Ho detto:

@property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;

dove avrei dovuto dire

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;

1
Strano, perché dovresti conservare IBOutlet? La loro gestione viene eseguita automaticamente per te.
jv42

3

Ho riscontrato EXC_BAD_ACCESS sull'iPhone solo durante il tentativo di eseguire un metodo C che includeva un array di grandi dimensioni. Il simulatore è stato in grado di darmi abbastanza memoria per eseguire il codice, ma non il dispositivo (l'array era un milione di caratteri, quindi era un po 'eccessivo!).

EXC_BAD_ACCESS si è verificato subito dopo il punto di ingresso del metodo e mi ha confuso per un bel po 'perché non si trovava da nessuna parte vicino alla dichiarazione dell'array.

Forse qualcun altro potrebbe trarre beneficio dal mio paio di ore di strappi di capelli.


3

Ho dimenticato di estrarre un puntatore non allocato da dealloc. Stavo ottenendo exc_bad_access sul mio rootView di un UINavigationController, ma solo a volte. Supponevo che il problema fosse nel rootView perché si stava bloccando a metà strada attraverso viewDidAppear {}. Si è rivelato accadere solo dopo che ho aperto la vista con la cattiva versione del dealloc {}, e basta!

"EXC_BAD_ACCESS" [Passaggio al processo 330] Nessuna memoria disponibile per programmare ora: non sicuro per chiamare malloc

Ho pensato che fosse un problema in cui stavo cercando di allocare ... non dove stavo provando a rilasciare un non-alloc, D'oh!


3

Come gestisco EXC_BAD_ACCESS

A volte sento che quando viene lanciato un errore EXC_BAD_ACCESS xcode mostrerà l'errore nella classe main.m senza fornire ulteriori informazioni su dove si verifica l'incidente (a volte).

In quei momenti possiamo impostare un Breakpoint eccezionale in Xcode in modo che quando viene rilevata un'eccezione verrà posizionato un breakpoint e intimi direttamente l'utente che si è verificato un arresto anomalo in quella riga

inserisci qui la descrizione dell'immagine


2

Le chiamate NSAssert () per convalidare i parametri del metodo sono piuttosto utili per rintracciare ed evitare anche il passaggio di zero.


2

Ho appena avuto questo problema. Per me il motivo era l'eliminazione di un oggetto gestito CoreData e il tentativo di leggerlo successivamente da un altro posto.


2

Ho eseguito il debug e il refactoring del codice per risolvere questo errore nelle ultime quattro ore. Un post sopra mi ha portato a vedere il problema:

Proprietà prima di:

startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS

Proprietà dopo:

startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];

addio EXC_BAD_ACCESS

Grazie mille per la tua risposta Ho lottato con questo problema tutto il giorno. Sei fantastico!


4
Non sovrascrivi immediatamente startPoint? Non credo che tu abbia bisogno di quella prima linea.
toxaq,

2
Non è assolutamente necessario allocare e inizializzare una variabile se la sovrascriverai immediatamente con un'altra. Stai solo perdendo l'oggetto nel primo compito.
dreamlax,

2

Solo per aggiungere

Lynda.com ha un fantastico DVD chiamato

Formazione essenziale per iPhone SDK

e il capitolo 6, lezione 3, parla di EXEC_BAD_ACCESS e del lavoro con Zombies.

È stato fantastico per me capire, non solo il codice di errore, ma come posso usare Zombies per ottenere maggiori informazioni sull'oggetto rilasciato.


2

Per verificare quale potrebbe essere l'errore

Usa NSZombieEnabled.

Per attivare la funzione NSZombieEnabled nell'applicazione:

Scegli Progetto> Modifica eseguibile attivo per aprire la finestra Informazioni eseguibile. Fai clic su Argomenti. Fai clic sul pulsante Aggiungi (+) nella sezione "Variabili da impostare nell'ambiente". Immettere NSZombieEnabled nella colonna Nome e SÌ nella colonna Valore. Assicurarsi che sia selezionato il segno di spunta per la voce NSZombieEnabled.

Ho trovato questa risposta su iPhoneSDK


2

Mi rendo conto che questo è stato chiesto qualche tempo fa, ma dopo aver letto questo thread, ho trovato la soluzione per XCode 4.2: Prodotto -> Modifica schema -> Scheda Diagnostica -> Abilita oggetti zombi

Mi ha aiutato a trovare un messaggio inviato a un oggetto deallocato.


2

Quando hai una ricorsione infinita, penso che puoi avere anche questo errore. Questo è stato un caso per me.


1

Anche un'altra possibilità: utilizzando i blocchi nelle code, potrebbe facilmente accadere che si provi ad accedere a un oggetto in un'altra coda, che è stata già disallocata in questo momento. In genere quando si tenta di inviare qualcosa alla GUI. Se il punto di interruzione dell'eccezione viene impostato in un posto strano, questa potrebbe essere la causa.


1

L'ho preso perché non stavo usando [self performSegueWithIdentifier:sender:]e -(void) prepareForSegue:(UIstoryboardSegue *)giusto


1

Non dimenticare il @simbolo durante la creazione di stringhe, trattando C-stringscome NSStringscauserà EXC_BAD_ACCESS.

Usa questo:

@"Some String"

Piuttosto che questo:

"Some String"

PS: in genere quando si popolano i contenuti di un file arraycon molti record.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.