EXC_BAD_ACCESS-Signal empfangen

290

Beim Bereitstellen der Anwendung auf dem Gerät wird das Programm nach einigen Zyklen mit dem folgenden Fehler beendet:

Program received signal: "EXC_BAD_ACCESS".

Das Programm läuft ohne Probleme auf dem iPhone-Simulator. Es wird auch debuggt und ausgeführt, solange ich die Anweisungen einzeln durchführe. Sobald ich es wieder laufen lasse, werde ich das EXC_BAD_ACCESSSignal treffen .

In diesem speziellen Fall handelte es sich zufällig um einen Fehler im Beschleunigungsmessercode. Es würde nicht im Simulator ausgeführt, weshalb es keine Fehler auslöste. Es wird jedoch ausgeführt, sobald es auf dem Gerät bereitgestellt wurde.

Die meisten Antworten auf diese Frage beziehen sich auf den allgemeinen EXC_BAD_ACCESSFehler, daher werde ich dies als Sammelbegriff für den gefürchteten Bad Access-Fehler offen lassen.

EXC_BAD_ACCESSwird normalerweise als Ergebnis eines illegalen Speicherzugriffs ausgelöst. Weitere Informationen finden Sie in den Antworten unten.

Haben Sie das EXC_BAD_ACCESSSignal schon einmal erlebt und wie sind Sie damit umgegangen?

Héctor Ramos
quelle

Antworten:

196

Aufgrund Ihrer Beschreibung vermute ich, dass die wahrscheinlichste Erklärung darin besteht, dass Sie einen Fehler in Ihrer Speicherverwaltung haben. Sie sagten, Sie arbeiten seit einigen Wochen an der iPhone-Entwicklung, aber nicht, ob Sie generell Erfahrung mit Objective C haben. Wenn Sie aus einem anderen Umfeld stammen, kann es eine Weile dauern, bis Sie die Speicherverwaltungsregeln wirklich verinnerlicht haben - es sei denn, Sie legen großen Wert darauf.

Denken Sie daran, dass Sie bei allem, was Sie von einer Zuweisungsfunktion (normalerweise der statischen Zuweisungsmethode, aber es gibt einige andere) oder einer Kopiermethode erhalten, auch der Speicher gehört und Sie ihn freigeben müssen, wenn Sie fertig sind.

Wenn Sie jedoch etwas von fast allem anderen zurückerhalten, einschließlich Factory-Methoden (z. B. [NSString stringWithFormat]), haben Sie eine Autorelease-Referenz, was bedeutet, dass es irgendwann in der Zukunft von anderem Code veröffentlicht werden kann - daher ist es wichtig, dass Sie dies benötigen um es über die unmittelbare Funktion hinaus zu behalten, die Sie behalten. Wenn Sie dies nicht tun, bleibt der Speicher möglicherweise während der Verwendung zugewiesen oder wird während des Emulatortests freigegeben, ist aber zufällig noch gültig. Es ist jedoch wahrscheinlicher, dass er freigegeben wird und beim Ausführen auf dem Gerät als fehlerhafter Zugriffsfehler angezeigt wird.

Der beste Weg, um diese Dinge aufzuspüren, und eine gute Idee (auch wenn es keine offensichtlichen Probleme gibt) ist, die App im Instrumenten-Tool auszuführen, insbesondere mit der Option "Lecks".

philsquared
quelle
2
Ich hatte einen Beschleunigungsmesser-Abtastcode, der für meine App nicht wichtig war und der nach dem Entfernen den Fehler beim fehlerhaften Zugriff beseitigte. Was Sinn macht, wenn man bedenkt, dass der Simulator keinen Beschleunigungsmesser hat. Ich finde es seltsam, dass dieser Code eine Woche lang unberührt existierte, bevor er diesen Fehler verursachte ...
Héctor Ramos
Ich bin neu in Objective-C, daher sollten die meisten meiner Probleme durch die Speicherverwaltung entstehen. Nach ein paar Jahren in C ++ habe ich in den letzten drei oder vier Jahren hauptsächlich Java verwendet, sodass die Speicherverwaltung verrostet ist. Danke für deine Antwort!
Héctor Ramos
4
Kein Problem - ich bin froh, dass Sie es behoben haben. Die Speicherverwaltung ist nicht wirklich schwierig - Sie müssen nur sicherstellen, dass Sie die Regeln lernen und sich an gute Gewohnheiten gewöhnen.
Philsquared
Das Problem, das ich hatte, scheint ausschließlich darin zu liegen, dass ich zu aggressiv bin, um von mir erstellte Strings (und solche) freizugeben. Ich bin mir immer noch nicht 100% sicher, was wann veröffentlicht werden soll, aber Phils Antwort hat sicherlich geholfen.
Pluckyglen
Wenn ich das richtig befolgt habe, cmculloh, ja, das war das Richtige. Sie besitzen nicht die Objektrückgabe von objectAtIndex.
Philsquared
101

Eine Hauptursache für EXC_BAD_ACCESS ist der Versuch, auf freigegebene Objekte zuzugreifen.

Lesen Sie dieses Dokument, um herauszufinden, wie Sie dieses Problem beheben können : DebuggingAutoReleasePool

Auch wenn Sie nicht glauben, dass Sie "automatisch freigegebene Objekte freigeben", gilt dies für Sie.

Diese Methode funktioniert sehr gut. Ich benutze es die ganze Zeit mit großem Erfolg !!

Zusammenfassend wird erläutert, wie Sie die NSZombie-Debugging-Klasse von Cocoa und das Befehlszeilen-Tool "malloc_history" verwenden, um genau zu ermitteln, auf welches freigegebene Objekt in Ihrem Code zugegriffen wurde.

Randnotiz:

Das Ausführen von Instrumenten und das Überprüfen auf Lecks hilft nicht bei der Fehlerbehebung bei EXC_BAD_ACCESS. Ich bin mir ziemlich sicher, dass Speicherlecks nichts mit EXC_BAD_ACCESS zu tun haben. Die Definition eines Lecks ist ein Objekt, auf das Sie keinen Zugriff mehr haben und das Sie daher nicht aufrufen können.

UPDATE: Ich benutze jetzt Instrumente, um Lecks zu debuggen. Wählen Sie in Xcode 4.2 Produkt-> Profil und beim Start von Instruments "Zombies".

Bentford
quelle
18
Diese Nebenbemerkung ist sehr wichtig. Lecks können EXC_BAD_ACCESS nicht verursachen (sie haben andere Probleme). Ich schrieb dies, um zu versuchen, Missverständnisse über EXC_BAD_ACCESS zu beseitigen. Loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco
4
Das Zombies-Tool in Xcode ist brillant! Ich fand den Täter in 3 Minuten nicht Stunden.
Aram Kocharyan
1
Der obige Link als Antwort ist nicht verfügbar. Zeigt den Fehler 404 nicht gefunden an.
Tejas
12

Ein EXC_BAD_ACCESS-Signal ist das Ergebnis der Übergabe eines ungültigen Zeigers an einen Systemaufruf. Ich habe heute eine mit einem Testprogramm unter OS X erhalten - ich habe eine nicht initialisierte Variable an übergeben pthread_join(), was auf einen früheren Tippfehler zurückzuführen war.

Ich bin mit der iPhone-Entwicklung nicht vertraut, aber Sie sollten alle Pufferzeiger, die Sie an Systemaufrufe übergeben, überprüfen. Erhöhen Sie die Warnstufe Ihres Compilers vollständig (verwenden Sie mit gcc die Optionen -Wallund -Wextra). Aktivieren Sie so viele Diagnosen wie möglich auf dem Simulator / Debugger.

Adam Rosenfield
quelle
8

Nach meiner Erfahrung wird dies im Allgemeinen durch einen illegalen Speicherzugriff verursacht. Überprüfen Sie alle Zeiger, insbesondere Objektzeiger, um sicherzustellen, dass sie initialisiert sind. Stellen Sie sicher, dass Ihre MainWindow.xib-Datei, falls Sie eine verwenden, ordnungsgemäß eingerichtet ist und über alle erforderlichen Verbindungen verfügt.

Wenn bei keiner dieser Überprüfungen auf dem Papier etwas auftaucht und dies nicht im Einzelschritt geschieht, versuchen Sie, den Fehler mit NSLog () -Anweisungen zu lokalisieren: Streuen Sie Ihren Code mit ihnen und verschieben Sie sie, bis Sie die verursachende Zeile isolieren der Fehler. Setzen Sie dann einen Haltepunkt in dieser Zeile und führen Sie Ihr Programm aus. Wenn Sie den Haltepunkt erreichen, überprüfen Sie alle Variablen und die darin enthaltenen Objekte, um festzustellen, ob etwas nicht so aussieht, wie Sie es erwarten. Ich würde besonders nach Variablen Ausschau halten, deren Objektklasse etwas ist, das Sie nicht erwartet haben. Wenn eine Variable ein UIWindow enthalten soll, aber stattdessen eine NSNotification enthält, kann sich derselbe zugrunde liegende Codefehler auf andere Weise manifestieren, wenn der Debugger nicht in Betrieb ist.

Brent Royal-Gordon
quelle
7

Ich habe gerade ein paar Stunden damit verbracht, einen EXC_BAD_ACCESS aufzuspüren, und festgestellt, dass NSZombies und andere Env-Vars mir nichts zu sagen schienen.

Für mich war es eine blöde NSLog-Anweisung mit Formatspezifizierern, aber es wurden keine Argumente übergeben.

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

Behoben von

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);
Scott Heaberlin
quelle
6

Die WWDC-Videos 2010 stehen allen Teilnehmern des Apple-Entwicklerprogramms zur Verfügung. Es gibt ein großartiges Video: "Sitzung 311 - Erweiterte Speicheranalyse mit Instrumenten", das einige Beispiele für die Verwendung von Zombies in Instrumenten und das Debuggen anderer Speicherprobleme zeigt.

Für einen Link zur Anmeldeseite klicken Sie HIER .

Jona
quelle
6

Keine vollständige Antwort, aber eine spezielle Situation, in der ich diese erhalten habe, ist der Versuch, auf ein Objekt zuzugreifen, das "gestorben" ist, weil ich versucht habe, Autorelease zu verwenden:

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

So habe ich dies beispielsweise tatsächlich als Objekt übergeben, um es zu "benachrichtigen" (als Zuhörer, Beobachter registriert, wie auch immer Sie es mögen), aber es war bereits gestorben, als die Benachrichtigung gesendet wurde und ich den EXC_BAD_ACCESS erhalten würde. Durch Ändern [[MyNetObject alloc] init]und späteres Freigeben wurde der Fehler behoben.

Ein weiterer Grund, warum dies passieren kann, ist beispielsweise, wenn Sie ein Objekt übergeben und versuchen, es zu speichern:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Wenn Sie später versuchen, auf myObjectDefinedInHeader zuzugreifen, können Probleme auftreten. Verwenden von:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

kann sein, was Sie brauchen. Natürlich sind dies nur ein paar Beispiele für das, was mir begegnet ist, und es gibt andere Gründe, aber diese können sich als schwer fassbar erweisen, deshalb erwähne ich sie. Viel Glück!

rauben
quelle
5

Nur um eine weitere Situation hinzuzufügen, in der dies passieren kann:

Ich hatte den Code:

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

Offensichtlich hatte ich vergessen, Speicher für die Zeichenfolge zuzuweisen:

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

behebt das Problem.

Gnuchu
quelle
Dies verursacht für mich keinen Fehler, da der String auf nil initialisiert wird und die Verwendung des Null-Objektmusters, das eine Methode auf nil aufruft, nichts bewirkt.
Liron Yahdav
5

Eine andere Methode zum Abfangen von EXC_BAD_ACCESS-Ausnahmen, bevor sie auftreten, ist der statische Analysator in XCode 4+.

Führen Sie den statischen Analysator mit Produkt> Analysieren aus (Umschalt + cmd + B). Wenn Sie auf vom Analysator generierte Nachrichten klicken, wird ein Diagramm auf Ihrer Quelle überlagert, das die Reihenfolge der Aufbewahrungen / Freigaben des betreffenden Objekts zeigt.

Geben Sie hier die Bildbeschreibung ein

ericsoco
quelle
5

Ich finde es nützlich, einen Haltepunkt für objc_exception_throw festzulegen. Auf diese Weise sollte der Debugger unterbrochen werden, wenn Sie EXC_BAD_ACCESS erhalten.

Anweisungen finden Sie hier DebuggingTechniques

Lyonanderson
quelle
4

Verwenden Sie die einfache Regel "Wenn Sie es nicht zugewiesen oder beibehalten haben, geben Sie es nicht frei".

Gammapunkt
quelle
1
Erweitern Sie diese Regel um "... kopieren Sie sie ..." und es sollte Ihnen gut gehen.
Bis zum
4

So debuggen Sie EXC_BAD_ACCESS

Schauen Sie sich den obigen Link an und machen Sie, was er sagt ... Nur eine kurze Anleitung zur Verwendung von NSZombies

Führen Sie die Anwendung aus und nachdem sie fehlgeschlagen ist (Sollte "Unterbrochen" statt "EXC_BAD_ACCESS" angezeigt werden ... überprüfen Sie die Konsole (Ausführen> Konsole) ... sollte dort eine Meldung angezeigt werden, auf welches Objekt zugegriffen werden soll.

-Ben

Ben Call
quelle
3

Ich habe in den letzten vier Stunden Code debuggt und umgestaltet, um diesen Fehler zu beheben. Ein Beitrag oben hat mich dazu gebracht, das Problem zu sehen:

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

Eigenschaft nach: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] beibehalten];

Auf Wiedersehen EXC_BAD_ACCESS


quelle
Ich habe einen ähnlichen Fehler gemacht. Ich habe vergessen, die Instanz, die den Absturz verursacht hat, erneut zu untersuchen, und habe Stunden damit verbracht, sie herauszufinden. Ihre Erfahrung hat mich dazu gebracht, meine herauszufinden. Vielen Dank!
David.Chu.ca
3

Ich hoffe, Sie geben die "Saite" frei, wenn Sie fertig sind!


quelle
3

Ich habe vergessen, mich in einer Init-Methode zurückzugeben ...;)

denbec
quelle
Dies sollte eine Warnung / ein Fehler zur Kompilierungszeit und kein EXC_BAD_ACCESS zur Laufzeit sein.
Stigi
3

Dies ist ein ausgezeichneter Thread. Hier ist meine Erfahrung: Ich habe das Schlüsselwort keep / assign in einer Eigenschaftsdeklaration durcheinander gebracht. Ich sagte:

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

wo ich hätte sagen sollen

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
narr4jesus
quelle
1
Seltsam, warum sollten Sie IBOutlet behalten müssen? Ihre Verwaltung erfolgt automatisch für Sie.
jv42
3

EXC_BAD_ACCESS ist auf dem iPhone nur beim Versuch aufgetreten, eine C-Methode auszuführen, die ein großes Array enthält. Der Simulator konnte mir genügend Speicher geben, um den Code auszuführen, aber nicht das Gerät (das Array bestand aus einer Million Zeichen, war also etwas übertrieben!).

EXC_BAD_ACCESS trat unmittelbar nach dem Einstiegspunkt der Methode auf und hatte mich eine ganze Weile verwirrt, da es sich nicht in der Nähe der Array-Deklaration befand.

Vielleicht könnte jemand anderes von meinen paar Stunden Haarziehen profitieren.

mblackwell8
quelle
3

Ich habe vergessen, einen nicht zugewiesenen Zeiger aus zu entfernen dealloc. Ich habe den exc_bad_access in meiner rootView eines UINavigationControllers erhalten, aber nur manchmal. Ich nahm an, dass das Problem in der rootView lag, weil es in der Mitte seiner viewDidAppear {} abstürzte. Es stellte sich heraus, dass es erst passierte, nachdem ich die Ansicht mit dem schlechten Dealloc {} veröffentlicht hatte, und das war es!

"EXC_BAD_ACCESS" [Umschalten auf Prozess 330] Derzeit ist kein Speicher zum Programmieren verfügbar: Unsicher, Malloc aufzurufen

Ich dachte, es sei ein Problem, bei dem ich versucht habe, eine Nichtzuweisung vorzunehmen ... nicht, bei dem ich versucht habe, eine Nichtzuweisung freizugeben, D'oh!

Josh
quelle
3

Wie ich mit EXC_BAD_ACCESS umgehe

Manchmal habe ich das Gefühl, dass wenn ein EXC_BAD_ACCESS-Fehler ausgelöst wird, xcode den Fehler in der main.m-Klasse anzeigt und keine zusätzlichen Informationen darüber gibt, wo der Absturz passiert (manchmal).

In diesen Zeiten können wir einen außergewöhnlichen Haltepunkt in Xcode festlegen, sodass beim Abfangen einer Ausnahme ein Haltepunkt gesetzt wird, der den Benutzer direkt darüber informiert, dass in dieser Zeile ein Absturz aufgetreten ist

Geben Sie hier die Bildbeschreibung ein

iPrabu
quelle
2

NSAssert () -Aufrufe zur Validierung von Methodenparametern sind sehr praktisch, um Nils aufzuspüren und zu vermeiden.

Ryan Townshend
quelle
2

Ich hatte gerade dieses Problem. Für mich war der Grund das Löschen eines von CoreData verwalteten Objekts und der Versuch, es anschließend von einem anderen Ort aus zu lesen.

konryd
quelle
2

Ich habe in den letzten vier Stunden Code debuggt und umgestaltet, um diesen Fehler zu beheben. Ein Beitrag oben hat mich dazu gebracht, das Problem zu sehen:

Eigentum vor:

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

Eigentum nach:

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

Auf Wiedersehen EXC_BAD_ACCESS

Vielen Dank für Ihre Antwort. Ich habe den ganzen Tag mit diesem Problem zu kämpfen. Du bist unglaublich!


quelle
4
Überschreiben Sie startPoint nicht sofort? Ich glaube nicht, dass Sie diese erste Zeile überhaupt brauchen.
Toxaq
2
Es ist absolut nicht erforderlich, eine Variable zuzuweisen und zu initialisieren, wenn Sie sie sofort mit einer anderen überschreiben möchten. Sie verlieren nur das Objekt in der ersten Zuordnung.
Dreamlax
2

Nur um hinzuzufügen

Lynda.com hat eine fantastische DVD namens

Grundlegendes Training für das iPhone SDK

In Kapitel 6, Lektion 3, geht es um EXEC_BAD_ACCESS und die Arbeit mit Zombies.

Es war toll für mich zu verstehen, nicht nur den Fehlercode, sondern auch, wie ich mit Zombies mehr Informationen über das freigegebene Objekt erhalten kann.

Balexandre
quelle
2

Um zu überprüfen, was der Fehler sein könnte

Verwenden Sie NSZombieEnabled.

So aktivieren Sie die NSZombieEnabled-Funktion in Ihrer Anwendung:

Wählen Sie "Projekt"> "Aktive ausführbare Datei bearbeiten", um das Fenster "Ausführbare Informationen" zu öffnen. Klicken Sie auf Argumente. Klicken Sie im Abschnitt „In der Umgebung festzulegende Variablen“ auf die Schaltfläche Hinzufügen (+). Geben Sie NSZombieEnabled in die Spalte Name und YES in die Spalte Value ein. Stellen Sie sicher, dass das Häkchen für den Eintrag NSZombieEnabled ausgewählt ist.

Ich habe diese Antwort auf iPhoneSDK gefunden

Zambono
quelle
2

Mir ist klar, dass dies vor einiger Zeit gefragt wurde, aber nachdem ich diesen Thread gelesen hatte, fand ich die Lösung für XCode 4.2: Produkt -> Schema bearbeiten -> Registerkarte Diagnose -> Zombie-Objekte aktivieren

Hat mir geholfen, eine Nachricht zu finden, die an ein freigegebenes Objekt gesendet wird.

Sean Aitken
quelle
2

Wenn Sie eine unendliche Rekursion haben, können Sie diesen Fehler auch haben. Dies war ein Fall für mich.

coolcool1994
quelle
1

Noch eine andere Möglichkeit: Wenn Sie Blöcke in Warteschlangen verwenden, kann es leicht vorkommen, dass Sie versuchen, auf ein Objekt in einer anderen Warteschlange zuzugreifen, die zu diesem Zeitpunkt bereits freigegeben wurde. Normalerweise, wenn Sie versuchen, etwas an die GUI zu senden. Wenn Ihr Ausnahme-Haltepunkt an einer fremden Stelle festgelegt wird, kann dies die Ursache sein.

Brainstray
quelle
1

Ich habe es bekommen, weil ich es nicht benutzt habe [self performSegueWithIdentifier:sender:]und -(void) prepareForSegue:(UIstoryboardSegue *)richtig

DHShah01
quelle
1

Vergessen Sie nicht das @Symbol , wenn Strings zu schaffen, die Behandlung C-stringsals NSStringsverursachen EXC_BAD_ACCESS.

Benutze das:

@"Some String"

Lieber als das:

"Some String"

PS - normalerweise beim Auffüllen von Inhalten arraymit vielen Datensätzen.

Artur
quelle