Signal EXC_BAD_ACCESS reçu

290

Lors du déploiement de l'application sur l'appareil, le programme se fermera après quelques cycles avec l'erreur suivante:

Program received signal: "EXC_BAD_ACCESS".

Le programme s'exécute sans aucun problème sur le simulateur d'iPhone, il sera également débogué et exécuté tant que je parcourrai les instructions une par une. Dès que je l'ai laissé fonctionner à nouveau, je vais frapper le EXC_BAD_ACCESSsignal.

Dans ce cas particulier, il s'agissait d'une erreur dans le code de l'accéléromètre. Il ne s'exécuterait pas dans le simulateur, c'est pourquoi il n'a généré aucune erreur. Cependant, il s'exécuterait une fois déployé sur l'appareil.

La plupart des réponses à cette question concernent l' EXC_BAD_ACCESSerreur générale , donc je vais laisser cela ouvert comme un fourre-tout pour l'erreur redoutée de mauvais accès.

EXC_BAD_ACCESSest généralement renvoyé à la suite d'un accès illégal à la mémoire. Vous pouvez trouver plus d'informations dans les réponses ci-dessous.

Avez-vous déjà rencontré le EXC_BAD_ACCESSsignal et comment l'avez-vous traité?

Héctor Ramos
la source

Réponses:

196

D'après votre description, je soupçonne que l'explication la plus probable est que vous avez une erreur dans la gestion de votre mémoire. Vous avez dit que vous travaillez sur le développement de l'iPhone depuis quelques semaines, mais pas si vous avez de l'expérience avec Objective C en général. Si vous venez d'un autre arrière-plan, cela peut prendre un peu de temps avant d'internaliser vraiment les règles de gestion de la mémoire - à moins que vous en fassiez un point important.

N'oubliez pas que tout ce que vous obtenez d'une fonction d'allocation (généralement la méthode d'allocation statique, mais il y en a quelques autres) ou d'une méthode de copie, vous possédez également la mémoire et devez la libérer lorsque vous avez terminé.

Mais si vous récupérez quelque chose d'autre, y compris des méthodes d'usine (par exemple [NSString stringWithFormat]), vous aurez une référence de libération automatique, ce qui signifie qu'elle pourrait être publiée à un moment donné dans le futur par un autre code - il est donc essentiel que si vous avez besoin pour le garder au-delà de la fonction immédiate que vous le conservez. Si vous ne le faites pas, la mémoire peut rester allouée pendant que vous l'utilisez, ou être libérée mais coïncidence toujours valide, pendant vos tests d'émulateur, mais est plus susceptible d'être libérée et de s'afficher comme de mauvaises erreurs d'accès lors de l'exécution sur l'appareil.

La meilleure façon de suivre ces choses, et une bonne idée de toute façon (même s'il n'y a aucun problème apparent) est d'exécuter l'application dans l'outil Instruments, en particulier avec l'option Leaks.

philsquared
la source
2
J'avais un code d'échantillonnage d'accéléromètre qui n'était pas vital pour mon application, ce qui, après suppression, a éliminé la mauvaise erreur d'accès. Ce qui est logique étant donné que le simulateur n'a pas d'accéléromètre. Je trouve bizarre que ce code ait existé, intact, pendant une semaine avant de provoquer cette erreur ...
Héctor Ramos
Je suis nouveau sur Objective-C, donc la plupart de mes problèmes devraient provenir de la gestion de la mémoire. Après quelques années en C ++, j'utilise principalement Java depuis trois ou quatre ans donc je suis devenu rouillé sur la gestion de la mémoire. Merci pour votre réponse!
Héctor Ramos
4
Pas de problème - content de l'avoir réparé. La gestion de la mémoire n'est pas vraiment difficile à maîtriser - il vous suffit de vous assurer d'apprendre les règles et de prendre de bonnes habitudes.
philsquared
Le problème que j'ai eu semble être exclusivement d'être trop agressif dans la libération de cordes (et autres) que je crée. Je ne suis toujours pas sûr à 100% de ce qui devrait sortir et quand, mais la réponse de Phil a certainement aidé.
pluckyglen
Si j'ai bien suivi, cmculloh, oui, c'était la bonne chose à faire. Vous ne possédez pas le retour d'objet de objectAtIndex.
philsquared
101

Une des principales causes d'EXC_BAD_ACCESS est d'essayer d'accéder aux objets libérés.

Pour savoir comment résoudre ce problème, lisez ce document: DebuggingAutoReleasePool

Même si vous ne pensez pas que vous "libérez des objets libérés automatiquement", cela s'applique à vous.

Cette méthode fonctionne extrêmement bien. Je l'utilise tout le temps avec beaucoup de succès !!

En résumé, cela explique comment utiliser la classe de débogage NSZombie de Cocoa et l'outil de ligne de commande "malloc_history" pour trouver exactement quel objet publié a été consulté dans votre code.

Sidenote:

L'exécution d'instruments et la recherche de fuites n'aideront pas à dépanner EXC_BAD_ACCESS. Je suis sûr que les fuites de mémoire n'ont rien à voir avec EXC_BAD_ACCESS. La définition d'une fuite est un objet auquel vous n'avez plus accès et vous ne pouvez donc pas l'appeler.

MISE À JOUR: J'utilise maintenant des instruments pour déboguer les fuites. Dans Xcode 4.2, choisissez Produit-> Profil et lorsque Instruments se lance, choisissez "Zombies".

Bentford
la source
18
Ce sidenote est très important. Les fuites ne peuvent pas provoquer EXC_BAD_ACCESS (elles ont d'autres problèmes). J'ai écrit ceci pour essayer de dissiper les idées fausses sur EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco
4
Cet outil zombies dans Xcode est génial! J'ai trouvé le coupable en 3 min et non en quelques heures.
Aram Kocharyan
1
lien ci-dessus en réponse n'est pas disponible. Affiche une erreur 404 introuvable.
Tejas
12

Un signal EXC_BAD_ACCESS est le résultat du passage d'un pointeur non valide à un appel système. J'en ai eu un plus tôt aujourd'hui avec un programme de test sur OS X - je passais une variable non initialisée à pthread_join(), qui était due à une faute de frappe antérieure.

Je ne suis pas familier avec le développement d'iPhone, mais vous devriez vérifier tous vos pointeurs de tampon que vous passez aux appels système. Augmentez complètement le niveau d'avertissement de votre compilateur (avec gcc, utilisez les options -Wallet -Wextra). Activez autant de diagnostics que possible sur le simulateur / débogueur.

Adam Rosenfield
la source
8

D'après mon expérience, cela est généralement dû à un accès illégal à la mémoire. Vérifiez tous les pointeurs, en particulier les pointeurs d'objet, pour vous assurer qu'ils sont initialisés. Assurez-vous que votre fichier MainWindow.xib, si vous en utilisez un, est correctement configuré, avec toutes les connexions nécessaires.

Si aucune de ces vérifications sur papier ne révèle quoi que ce soit et que cela ne se produit pas en une seule étape, essayez de localiser l'erreur avec les instructions NSLog (): saupoudrez votre code avec elles, déplacez-les jusqu'à ce que vous isoliez la ligne qui cause l'erreur. Définissez ensuite un point d'arrêt sur cette ligne et exécutez votre programme. Lorsque vous atteignez le point d'arrêt, examinez toutes les variables, et les objets qu'elles contiennent, pour voir si quelque chose ne ressemble pas à ce que vous attendez. Je garderais particulièrement un œil sur les variables dont la classe d'objets est quelque chose que vous n'attendiez pas. Si une variable est censée contenir une UIWindow mais qu'elle contient une NSNotification à la place, la même erreur de code sous-jacente pourrait se manifester d'une manière différente lorsque le débogueur n'est pas en fonctionnement.

Brent Royal-Gordon
la source
7

Je viens de passer quelques heures à suivre un EXC_BAD_ACCESS et j'ai trouvé que NSZombies et d'autres vars env ne semblaient rien me dire.

Pour moi, c'était une stupide déclaration NSLog avec des spécificateurs de format mais aucun argument n'a été passé.

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

Fixé par

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

Les vidéos de la WWDC 2010 sont disponibles pour tous les participants au programme pour développeurs Apple. Il y a une excellente vidéo: "Session 311 - Advanced Memory Analysis with Instruments" qui montre quelques exemples d'utilisation de zombies dans des instruments et de débogage d'autres problèmes de mémoire.

Pour un lien vers la page de connexion, cliquez ICI .

Jonas
la source
6

Pas une réponse complète, mais une situation spécifique où j'ai reçu ceci est lorsque j'essaie d'accéder à un objet qui est «mort» parce que j'ai essayé d'utiliser la libération automatique:

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

Ainsi, par exemple, je passais en fait cela comme un objet à `` notifier '' (enregistré comme auditeur, observateur, quel que soit l'idiome que vous aimez), mais il était déjà mort une fois la notification envoyée et j'obtiendrais l'EXC_BAD_ACCESS. Le modifier [[MyNetObject alloc] init]et le publier plus tard, le cas échéant, a résolu l'erreur.

Cela peut également se produire par exemple si vous passez un objet et essayez de le stocker:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Plus tard, lorsque vous essayez d'accéder à myObjectDefinedInHeader, vous pouvez rencontrer des problèmes. En utilisant:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

peut être ce dont vous avez besoin. Bien sûr, ce ne sont que quelques exemples de ce que j'ai rencontré et il y a d'autres raisons, mais celles-ci peuvent se révéler insaisissables, donc je les mentionne. Bonne chance!

Rob
la source
5

Juste pour ajouter une autre situation où cela peut se produire:

J'avais le code:

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

Évidemment, j'avais oublié d'allouer de la mémoire à la chaîne:

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

résout le problème.

gnuchu
la source
Cela ne cause aucune erreur pour moi car la chaîne est initialisée à nil et l'utilisation du modèle d'objet nul appelant une méthode sur nil ne fait rien.
Liron Yahdav
5

Une autre méthode pour intercepter les exceptions EXC_BAD_ACCESS avant qu'elles ne se produisent est l' analyseur statique , dans XCode 4+.

Exécutez l'analyseur statique avec Produit> Analyser (shift + cmd + B). En cliquant sur les messages générés par l'analyseur, vous superposerez un diagramme sur votre source montrant la séquence de rétention / libération de l'objet incriminé.

entrez la description de l'image ici

ericsoco
la source
5

Je trouve utile de définir un point d'arrêt sur objc_exception_throw. De cette façon, le débogueur devrait s'arrêter lorsque vous obtenez l'EXC_BAD_ACCESS.

Les instructions peuvent être trouvées ici DebuggingTechniques

lyonanderson
la source
4

Utilisez la règle simple "si vous ne l'avez pas alloué ou conservé, ne le libérez pas".

Gamma-Point
la source
1
Développez cette règle par "... copiez-la ..." et tout ira bien.
Jusqu'au
4

Comment déboguer EXC_BAD_ACCESS

Consultez le lien ci-dessus et faites comme il dit .... Juste quelques instructions rapides pour utiliser NSZombies

Exécutez l'application et après son échec (Devrait afficher "Interrompu" plutôt que "EXC_BAD_ACCESS" ... vérifiez la console (Exécuter> Console) ... il devrait y avoir un message indiquant maintenant à quel objet il essayait d'accéder.

-Ben

Ben Call
la source
3

J'ai débogué et refactorisé du code pour résoudre cette erreur au cours des quatre dernières heures. Un post ci-dessus m'a amené à voir le problème:

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

Propriété après: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] conserver];

Au revoir EXC_BAD_ACCESS


la source
J'ai fait une erreur similaire. J'ai oublié de réactiver l'instance qui a provoqué le crash et j'ai passé des heures à le comprendre. Votre expérience m'a permis de découvrir la mienne. Merci!
David.Chu.ca
3

J'espère que vous relâchez la «chaîne» lorsque vous avez terminé!


la source
3

J'ai oublié de retourner moi-même dans une méthode init ...;)

denbec
la source
Il doit s'agir d'un avertissement / erreur de compilation et non d'un EXC_BAD_ACCESS pendant l'exécution.
stigi
3

C'est un excellent fil. Voici mon expérience: je me suis trompé avec le mot-clé retenir / affecter sur une déclaration de propriété. J'ai dit:

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

où j'aurais dû dire

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
fool4jesus
la source
1
Étrange, pourquoi auriez-vous besoin de conserver IBOutlet? Leur gestion se fait automatiquement pour vous.
jv42
3

J'ai rencontré EXC_BAD_ACCESS sur l'iPhone uniquement en essayant d'exécuter une méthode C qui comprenait un grand tableau. Le simulateur a pu me donner suffisamment de mémoire pour exécuter le code, mais pas l'appareil (le tableau comptait un million de caractères, donc c'était un peu excessif!).

L'EXC_BAD_ACCESS s'est produit juste après le point d'entrée de la méthode et m'a laissé perplexe pendant un bon moment car il était loin de la déclaration du tableau.

Peut-être que quelqu'un d'autre pourrait profiter de mes quelques heures de tirage.

mblackwell8
la source
3

Vous avez oublié de retirer un pointeur non alloué dealloc. J'obtenais l'exc_bad_access sur mon rootView d'un UINavigationController, mais seulement parfois. J'ai supposé que le problème était dans rootView car il se bloquait à mi-chemin dans son viewDidAppear {}. Cela ne s'est produit qu'après avoir sauté la vue avec la mauvaise version de dealloc {}, et c'était tout!

"EXC_BAD_ACCESS" [Passage au processus 330] Pas de mémoire disponible pour programmer maintenant: dangereux d'appeler malloc

Je pensais que c'était un problème où j'essayais d'allouer ... pas où j'essayais de libérer un non-alloc, D'oh!

Josh
la source
3

Comment je traite avec EXC_BAD_ACCESS

Parfois, je pense que lorsqu'une erreur EXC_BAD_ACCESS est levée, xcode affichera l'erreur dans la classe main.m ne donnant aucune information supplémentaire sur l'endroit où le crash se produit (Parfois).

Dans ces moments, nous pouvons définir un point d'arrêt exceptionnel dans Xcode afin que lorsqu'une exception est détectée, un point d'arrêt soit placé et intime directement l'utilisateur que le crash s'est produit sur cette ligne

entrez la description de l'image ici

iPrabu
la source
2

Les appels NSAssert () pour valider les paramètres de la méthode sont assez pratiques pour retrouver et éviter le passage de nils.

Ryan Townshend
la source
2

Je viens d'avoir ce problème. Pour moi, la raison était de supprimer un objet géré CoreData et d'essayer de le lire depuis un autre endroit.

Konryd
la source
2

J'ai débogué et refactorisé du code pour résoudre cette erreur au cours des quatre dernières heures. Un post ci-dessus m'a amené à voir le problème:

Propriété avant:

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

Propriété après:

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

Au revoir EXC_BAD_ACCESS

Merci beaucoup pour votre réponse. J'ai eu du mal avec ce problème toute la journée. Vous êtes génial!


la source
4
N'êtes-vous pas en train d'écraser immédiatement startPoint? Je ne pense pas que vous ayez besoin de cette première ligne.
toxaq
2
Il n'est absolument pas nécessaire d'allouer et d'initialiser une variable si vous allez immédiatement la remplacer par une autre. Vous faites juste fuir l'objet lors de la première affectation.
dreamlax
2

Juste pour ajouter

Lynda.com a un fantastique DVD appelé

iPhone Essential SDK Training

et le chapitre 6, leçon 3, est consacré à EXEC_BAD_ACCESS et à l'utilisation des zombies.

C'était génial pour moi de comprendre, pas seulement le code d'erreur mais comment puis-je utiliser Zombies pour obtenir plus d'informations sur l'objet publié.

balexandre
la source
2

Pour vérifier quelle pourrait être l'erreur

Utilisez NSZombieEnabled.

Pour activer la fonction NSZombieEnabled dans votre application:

Choisissez Projet> Modifier l'exécutable actif pour ouvrir la fenêtre Info exécutable. Cliquez sur Arguments. Cliquez sur le bouton ajouter (+) dans la section «Variables à définir dans l'environnement». Entrez NSZombieEnabled dans la colonne Nom et YES dans la colonne Valeur. Assurez-vous que la coche pour l'entrée NSZombieEnabled est sélectionnée.

J'ai trouvé cette réponse sur iPhoneSDK

zambono
la source
2

Je me rends compte que cela a été demandé il y a quelque temps, mais après avoir lu ce fil, j'ai trouvé la solution pour XCode 4.2: Produit -> Modifier le schéma -> Onglet Diagnostics -> Activer les objets Zombie

M'a aidé à trouver un message envoyé à un objet désalloué.

Sean Aitken
la source
2

Lorsque vous avez une récursion infinie, je pense que vous pouvez également avoir cette erreur. Ce fut un cas pour moi.

coolcool1994
la source
1

Encore une autre possibilité: en utilisant des blocs dans les files d'attente, il peut facilement arriver que vous essayiez d'accéder à un objet dans une autre file d'attente, qui a déjà été désallouée à ce moment. Généralement, lorsque vous essayez d'envoyer quelque chose à l'interface graphique. Si votre point d'arrêt d'exception est défini à un endroit étrange, cela peut être la cause.

brainray
la source
1

Je l'ai eu parce que je n'utilisais pas [self performSegueWithIdentifier:sender:]et à -(void) prepareForSegue:(UIstoryboardSegue *)droite

DHShah01
la source
1

N'oubliez pas le @symbole lors de la création de chaînes, en traitant C-stringscomme NSStringsil en résultera EXC_BAD_ACCESS.

Utilisez ceci:

@"Some String"

Plutôt que cela:

"Some String"

PS - généralement lors du remplissage du contenu d'un arrayavec de nombreux enregistrements.

Artur
la source