Señal EXC_BAD_ACCESS recibida

290

Al implementar la aplicación en el dispositivo, el programa se cerrará después de algunos ciclos con el siguiente error:

Program received signal: "EXC_BAD_ACCESS".

El programa se ejecuta sin problemas en el simulador de iPhone, también se depurará y ejecutará siempre que siga las instrucciones una por una. Tan pronto como lo deje correr nuevamente, presionaré la EXC_BAD_ACCESSseñal.

En este caso particular, resultó ser un error en el código del acelerómetro. No se ejecutaría dentro del simulador, por lo que no arrojó ningún error. Sin embargo, se ejecutaría una vez implementado en el dispositivo.

La mayoría de las respuestas a esta pregunta se refieren al EXC_BAD_ACCESSerror general , por lo que lo dejaré abierto como una trampa para el temido error de acceso incorrecto.

EXC_BAD_ACCESSnormalmente se produce como resultado de un acceso ilegal a la memoria. Puede encontrar más información en las respuestas a continuación.

¿Has encontrado la EXC_BAD_ACCESSseñal antes y cómo la manejaste?

Héctor Ramos
fuente

Respuestas:

196

Según su descripción, sospecho que la explicación más probable es que tiene algún error en la administración de su memoria. Dijiste que has estado trabajando en el desarrollo de iPhone durante algunas semanas, pero no si tienes experiencia con Objective C en general. Si ha venido de otro entorno, puede pasar un poco de tiempo antes de que realmente internalice las reglas de administración de memoria, a menos que haga un gran comentario.

Recuerde, todo lo que obtiene de una función de asignación (generalmente el método de asignación estática, pero hay algunos otros), o un método de copia, también posee la memoria y debe liberarla cuando haya terminado.

Pero si obtiene algo de casi cualquier otra cosa, incluidos los métodos de fábrica (p [NSString stringWithFormat]. Ej. ), Tendrá una referencia de liberación automática, lo que significa que podría ser publicado en algún momento en el futuro por otro código, por lo que es vital que si lo necesita para mantenerlo más allá de la función inmediata que lo retiene. Si no lo hace, la memoria puede permanecer asignada mientras la está utilizando, o liberarse, pero casualmente sigue siendo válida, durante la prueba del emulador, pero es más probable que se libere y aparezca como errores de acceso incorrectos cuando se ejecuta en el dispositivo.

La mejor manera de rastrear estas cosas, y una buena idea de todos modos (incluso si no hay problemas aparentes) es ejecutar la aplicación en la herramienta Instrumentos, especialmente con la opción Fugas.

philsquared
fuente
2
Tenía un código de muestreo de acelerómetro que no era vital para mi aplicación, que después de eliminarlo eliminó el error de acceso incorrecto. Lo que tiene sentido teniendo en cuenta que el simulador no tiene un acelerómetro. Me parece extraño que este código haya existido, intacto, durante una semana antes de causar este error ...
Héctor Ramos
Soy nuevo en Objective-C, por lo que la mayoría de mis problemas deberían surgir de la administración de la memoria. Después de algunos años en C ++, he estado usando principalmente Java durante los últimos tres o cuatro años, así que me he oxidado en la administración de la memoria. ¡Gracias por tu respuesta!
Héctor Ramos
44
No hay problema, me alegro de que lo haya solucionado. La gestión de la memoria no es realmente difícil de controlar, solo necesita asegurarse de aprender las reglas y adquirir buenos hábitos.
philsquared
El problema que he tenido parece ser exclusivamente con ser demasiado agresivo al liberar cadenas (y demás) que creo. Todavía no estoy 100% seguro de qué debería lanzarse y cuándo, pero la respuesta de Phil ciertamente ayudó.
pluckyglen
Si seguí eso correctamente, cmculloh, sí, eso fue lo correcto. No es propietario del retorno de objeto de objectAtIndex.
philsquared
101

Una causa importante de EXC_BAD_ACCESS es intentar acceder a los objetos liberados.

Para saber cómo solucionar este problema, lea este documento: DebuggingAutoReleasePool

Incluso si no cree que está "liberando objetos liberados automáticamente", esto se aplicará a usted.

Este método funciona extremadamente bien. Lo uso todo el tiempo con gran éxito !!

En resumen, esto explica cómo usar la clase de depuración NSZombie de Cocoa y la herramienta de línea de comando "malloc_history" para encontrar exactamente a qué objeto liberado se ha accedido en su código.

Nota al margen:

La ejecución de instrumentos y la comprobación de fugas no ayudarán a solucionar EXC_BAD_ACCESS. Estoy bastante seguro de que las pérdidas de memoria no tienen nada que ver con EXC_BAD_ACCESS. La definición de una fuga es un objeto al que ya no tiene acceso y, por lo tanto, no puede llamarlo.

ACTUALIZACIÓN: ahora uso instrumentos para depurar fugas. Desde Xcode 4.2, elija Producto-> Perfil y cuando se lance Instrumentos, elija "Zombis".

Bentford
fuente
18
Esa nota al margen es muy importante. Las fugas no pueden causar EXC_BAD_ACCESS (tienen otros problemas). Escribí esto para tratar de aclarar conceptos erróneos sobre EXC_BAD_ACCESS loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco
44
¡Esa herramienta de zombies en Xcode es brillante! Encontré al culpable en 3 minutos, no en horas.
Aram Kocharyan
1
el enlace de arriba en respuesta no está disponible. Muestra el error 404 no encontrado.
Tejas
12

Una señal EXC_BAD_ACCESS es el resultado de pasar un puntero no válido a una llamada del sistema. Hoy recibí uno con un programa de prueba en OS X: estaba pasando una variable no inicializada pthread_join(), debido a un error tipográfico anterior.

No estoy familiarizado con el desarrollo de iPhone, pero debe verificar dos veces todos los punteros de búfer que pasa a las llamadas del sistema. Sube el nivel de advertencia de tu compilador hasta el final (con gcc, usa las opciones -Wally -Wextra). Habilite tantos diagnósticos en el simulador / depurador como sea posible.

Adam Rosenfield
fuente
8

En mi experiencia, esto generalmente es causado por un acceso ilegal a la memoria. Verifique todos los punteros, especialmente los punteros de objeto, para asegurarse de que estén inicializados. Asegúrese de que su archivo MainWindow.xib, si está utilizando uno, esté configurado correctamente, con todas las conexiones necesarias.

Si ninguna de esas comprobaciones en papel revela algo, y no sucede cuando se realiza un solo paso, intente localizar el error con las instrucciones NSLog (): espolvoree su código con ellas, muévalas hasta que aísle la línea que está causando el error. Luego establezca un punto de interrupción en esa línea y ejecute su programa. Cuando llegue al punto de ruptura, examine todas las variables y los objetos en ellas, para ver si algo no se ve como esperaba. Especialmente estaré atento a las variables cuya clase de objeto es algo que no esperaba. Si se supone que una variable contiene una UIWindow pero en su lugar tiene una NSNotification, el mismo error de código subyacente podría manifestarse de manera diferente cuando el depurador no está en funcionamiento.

Brent Royal-Gordon
fuente
7

Acabo de pasar un par de horas rastreando un EXC_BAD_ACCESS y descubrí que NSZombies y otros entornos no parecían decirme nada.

Para mí, fue una declaración estúpida de NSLog con especificadores de formato, pero no pasó ningún argumento.

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

Arreglado por

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

Los videos WWDC 2010 están disponibles para cualquier participante en el programa de desarrolladores de Apple. Hay un gran video: "Sesión 311 - Análisis avanzado de memoria con instrumentos" que muestra algunos ejemplos de uso de zombis en instrumentos y depuración de otros problemas de memoria.

Para obtener un enlace a la página de inicio de sesión, haga clic AQUÍ .

Jonás
fuente
6

No es una respuesta completa, pero una situación específica en la que he recibido esto es cuando intento acceder a un objeto que 'murió' porque intenté usar la liberación automática:

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

Entonces, por ejemplo, en realidad estaba pasando esto como un objeto para 'notificar' (lo registré como oyente, observador, cualquier idioma que desee) pero ya había muerto una vez que se envió la notificación y obtendría el EXC_BAD_ACCESS. Cambiarlo [[MyNetObject alloc] init]y liberarlo más tarde, según corresponda, resolvió el error.

Otra razón por la que esto puede suceder es, por ejemplo, si pasa un objeto e intenta almacenarlo:

myObjectDefinedInHeader = aParameterObjectPassedIn;

Más adelante, cuando intente acceder a myObjectDefinedInHeader, puede tener problemas. Utilizando:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

puede ser lo que necesitas Por supuesto, estos son solo un par de ejemplos de lo que me he encontrado y hay otras razones, pero pueden resultar escurridizas, así que las menciono. ¡Buena suerte!

Robar
fuente
5

Solo para agregar otra situación en la que esto puede suceder:

Tenía el código

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

Obviamente me había olvidado de asignar memoria para la cadena:

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

soluciona el problema

gnuchu
fuente
Esto no me causa ningún error porque la cadena se inicializa en nil y el uso del patrón de objeto nulo que llama a un método en nil no hace nada.
Liron Yahdav
5

Otro método para detectar excepciones EXC_BAD_ACCESS antes de que ocurran es el analizador estático , en XCode 4+.

Ejecute el analizador estático con Producto> Analizar (shift + cmd + B). Al hacer clic en cualquier mensaje generado por el analizador, se superpondrá un diagrama en su fuente que muestra la secuencia de retenciones / liberaciones del objeto ofensor.

ingrese la descripción de la imagen aquí

ericsoco
fuente
5

Me resulta útil establecer un punto de interrupción en objc_exception_throw. De esa forma, el depurador debería romperse cuando obtenga EXC_BAD_ACCESS.

Las instrucciones se pueden encontrar aquí Técnicas de depuración

lyonanderson
fuente
4

Use la regla simple de "si no lo asignó o retuvo, no lo libere".

Punto gamma
fuente
1
Expande esa regla con "... cópiala ..." y deberías estar bien.
Hasta el
4

Cómo depurar EXC_BAD_ACCESS

Mira el enlace de arriba y haz lo que dice ... Solo algunas instrucciones rápidas para usar NSZombies

Ejecute la aplicación y luego de que falle (Debería mostrar "Interrumpido" en lugar de "EXC_BAD_ACCESS" ... verifique la Consola (Ejecutar> Consola) ... debería haber un mensaje que indique qué objeto estaba intentando acceder.

-Ben

Ben Call
fuente
3

He estado depurando y refactorizando código para resolver este error durante las últimas cuatro horas. Una publicación anterior me llevó a ver el problema:

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

Propiedad después de: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] retener];

Adiós EXC_BAD_ACCESS


fuente
Cometí un error similar. Olvidé leer la instancia que causó el colapso y pasé horas para resolverlo. Tu experiencia me iluminó para descubrir la mía. ¡Gracias!
David.Chu.ca
3

¡Espero que estés soltando la 'cuerda' cuando hayas terminado!


fuente
3

Olvidé regresar a mí mismo en un método init ...;)

denbec
fuente
Esto debería ser una advertencia / error en tiempo de compilación y no un EXC_BAD_ACCESS durante el tiempo de ejecución.
stigi
3

Este es un excelente hilo. Aquí está mi experiencia: me equivoqué con la palabra clave de retención / asignación en una declaración de propiedad. Dije:

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

donde debería haber dicho

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
fool4jesus
fuente
1
Extraño, ¿por qué necesitarías retener IBOutlet? Su gestión se realiza automáticamente.
jv42
3

Encontré EXC_BAD_ACCESS en el iPhone solo mientras intentaba ejecutar un método C que incluía una gran matriz. El simulador pudo darme suficiente memoria para ejecutar el código, pero no el dispositivo (la matriz tenía un millón de caracteres, ¡así que era un poco excesivo!).

El EXC_BAD_ACCESS ocurrió justo después del punto de entrada del método y me confundió durante bastante tiempo porque no estaba cerca de la declaración de la matriz.

Quizás alguien más podría beneficiarse de mis dos horas de tirones de cabello.

mblackwell8
fuente
3

Olvidé sacar un puntero no asignado de dealloc. Estaba obteniendo el exc_bad_access en mi rootView de un UINavigationController, pero solo a veces. Supuse que el problema estaba en rootView porque se estaba bloqueando a la mitad de su viewDidAppear {}. Resultó que solo sucedió después de que aparecí la vista con el mal lanzamiento de Dealloc {}, ¡y eso fue todo!

"EXC_BAD_ACCESS" [Cambiando al proceso 330] No hay memoria disponible para programar ahora: no es seguro llamar a malloc

Pensé que era un problema donde estaba tratando de asignar ... no donde estaba tratando de liberar un no-alloc, ¡Oh!

Josh
fuente
3

Cómo trato con EXC_BAD_ACCESS

A veces siento que cuando se produce un error EXC_BAD_ACCESS, xcode mostrará el error en la clase main.m sin dar información adicional de dónde ocurre el bloqueo (a veces).

En esos momentos, podemos establecer un punto de interrupción excepcional en Xcode para que cuando se detecte una excepción, se coloque un punto de interrupción e íntimamente al usuario que el bloqueo ha ocurrido en esa línea

ingrese la descripción de la imagen aquí

iPrabu
fuente
2

Las llamadas NSAssert () para validar los parámetros del método son bastante útiles para rastrear y evitar pasar nulos también.

Ryan Townshend
fuente
2

acabo de tener este problema. Para mí, la razón fue eliminar un objeto administrado por CoreData e intentar leerlo luego desde otro lugar.

konryd
fuente
2

He estado depurando y refactorizando código para resolver este error durante las últimas cuatro horas. Una publicación anterior me llevó a ver el problema:

Propiedad antes:

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

Propiedad después de:

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

Adiós EXC_BAD_ACCESS

Muchas gracias por tu respuesta. He estado luchando con este problema todo el día. ¡Eres increíble!


fuente
44
¿No estás sobrescribiendo inmediatamente startPoint? No creo que necesites esa primera línea.
toxaq
2
No hay absolutamente ninguna necesidad de asignar e inicializar una variable si inmediatamente va a sobrescribirla con otra. Solo estás filtrando el objeto en la primera tarea.
dreamlax
2

Solo para agregar

Lynda.com tiene un fantástico DVD llamado

iPhone SDK Essential Training

y el Capítulo 6, Lección 3, trata de EXEC_BAD_ACCESS y de trabajar con Zombies.

Fue genial para mí entender, no solo el código de error, sino cómo puedo usar Zombies para obtener más información sobre el objeto lanzado.

balexandre
fuente
2

Para verificar cuál puede ser el error

Use NSZombieEnabled.

Para activar la instalación NSZombieEnabled en su aplicación:

Elija Proyecto> Editar ejecutable activo para abrir la ventana de información ejecutable. Haz clic en Argumentos. Haga clic en el botón Agregar (+) en la sección "Variables para establecer en el entorno". Ingrese NSZombieEnabled en la columna Nombre y SÍ en la columna Valor. Asegúrese de que la marca de verificación para la entrada NSZombieEnabled esté seleccionada.

Encontré esta respuesta en iPhoneSDK

zambono
fuente
2

Me doy cuenta de que esto se preguntó hace algún tiempo, pero después de leer este hilo, encontré la solución para XCode 4.2: Producto -> Editar esquema -> Pestaña Diagnóstico -> Habilitar objetos zombi

Me ayudó a encontrar un mensaje enviado a un objeto desasignado.

Sean Aitken
fuente
2

Cuando tienes una recursión infinita, creo que también puedes tener este error. Este fue un caso para mí.

coolcool1994
fuente
1

Incluso otra posibilidad: al usar bloques en las colas, puede suceder fácilmente que intente acceder a un objeto en otra cola, que ya se ha desasignado en este momento. Por lo general, cuando intenta enviar algo a la GUI. Si su punto de interrupción de excepción se establece en un lugar extraño, entonces esta podría ser la causa.

brainray
fuente
1

Lo entendí porque no estaba usando [self performSegueWithIdentifier:sender:]y -(void) prepareForSegue:(UIstoryboardSegue *)correcto

DHShah01
fuente
1

No olvide el @símbolo al crear cadenas, tratando C-stringscomo NSStringscausará EXC_BAD_ACCESS.

Utilizar este:

@"Some String"

En vez de esto:

"Some String"

PS: normalmente cuando se rellenan contenidos de un arrayarchivo con muchos registros.

Artur
fuente