iphone - ¿Cómo encontrar la causa de un error malloc "double free"?
objective-c memory-management (13)
Estoy programando una aplicación en Objective-C y estoy obteniendo este error:
MyApp (2121,0xb0185000) malloc: *** error para el objeto 0x1068310: doble libre
*** establecer un punto de interrupción en malloc_error_break para depurar
Está sucediendo cuando lanzo un NSAutoreleasePool y no puedo descifrar qué objeto estoy liberando dos veces.
¿Cómo configuro su punto de inflexión?
¿Hay alguna manera de saber qué es este "objeto 0x1068310"?
Agregar un punto de corte simbólico en Xcode 4
Solo una actualización para hacer que esto sea relevante para Xcode 4 ...
De la guía de usuario de Xcode 4 :
Para agregar un punto de interrupción simbólico. . .
- En la esquina inferior izquierda del navegador de punto de interrupción, haz clic en el botón Agregar.
- Elija Agregar punto de ruptura simbólico.
- Ingrese el nombre del símbolo en el campo Símbolo.
- Haga clic en Listo.
Abra la consola del depurador presionando Cmd + Shift + R. Ahí, escribe
break malloc_error_break
para establecer un punto de interrupción al comienzo de la función malloc_error_break
.
Si desea averiguar qué objeto se encuentra en la dirección 0x1068310, puede escribir lo siguiente en la consola del depurador:
print-object 0x1068310
Por supuesto, tienes que hacer esto mientras el objeto todavía está vivo: si el objeto ya se ha liberado para cuando lo haces, entonces esto no funcionará.
Cuando un objeto es "doblemente liberado", la causa más común es que liberas (innecesariamente) un objeto liberado automáticamente, y luego se libera automáticamente cuando se vacía el grupo de autorrelease que lo contiene.
Descubrí que la mejor manera de rastrear la versión extra es usar la variable de entorno NSZombieEnabled para el ejecutable afectado en Xcode. Para obtener un resumen rápido de cómo usarlo, consulte esta página wiki de CocoaDev . (Además de esta página, Apple ha documentado algunos consejos increíblemente oscuros pero útiles para depurar código en Xcode, algunos de los cuales han guardado mi bacon más de unas pocas veces. Sugiero consultar esta nota técnica en developer.apple.com - enlace salta a la sección en el marco de la Fundación Cocoa).
Editar: a menudo puede rastrear el objeto infractor dentro del depurador Xcode, pero a menudo es mucho más fácil si utiliza instrumentos para ayudarlo. Desde Xcode, seleccione Ejecutar → Iniciar con la herramienta de rendimiento → Asignación de objetos y podrá rastrear el objeto infractor hasta el lugar donde se creó. (Esto funcionará mejor si está habilitado zombies como se discutió anteriormente.) Nota: Snow Leopard agrega una herramienta Zombies a Instrumentos, accesible desde el menú Ejecutar también. ¡Puede valer los $ 29 solos! ;-)
También hay una pregunta relacionada SO aquí .
Descubrirá qué es el objeto cuando interrumpa el depurador. Solo busca la pila de llamadas y encontrarás dónde la liberas. Eso te dirá qué objeto es.
La forma más fácil de establecer el punto de interrupción es:
- Vaya a Ejecutar -> Mostrar -> Puntos de interrupción ( ALT - Comando - B )
- Desplázate hasta el final de la lista y agrega el símbolo
malloc_error_break
En Xcode, haga clic a la izquierda del número de línea para establecer un punto de interrupción. Luego puede ejecutarlo haciendo una "compilación y depuración".
Se recomienda no tener un objeto que cree que se autorelease
ya que la memoria es un producto básico en el iPhone. Apple recomienda llamar explícitamente a la release
.
Encuentre los pasos a continuación para saber cómo encontrar el objeto que es gratis y bloquear la aplicación.
1) Haga clic en el " Navegador de punto de interrupción ".
2) Luego haga clic en el botón " + " que se encuentra debajo.
3) Agregue el " punto de corte simbólico ... " de la lista.
4) Agregue la palabra clave " malloc_error_break " en la opción " Símbolo ".
O también puede consultar la siguiente presentación de GIF.
Este es el aspecto del punto de interrupción malloc_error_break en la ventana Puntos de corte en Xcode. Necesito marcar las casillas para que funcione.
texto alternativo http://www.martijnthe.nl/wp-content/uploads/2009/08/Afbeelding-1.png
Esto generalmente es causado por algún inspector, como Safari o Safari Preview. Consulte la post o post y la question .
Elimine la selección de AutoMatically Show Web ...., eliminará este problema.
Tenga en cuenta que solo safari de cerca o vista previa de safari no eliminará este problema. Y debe anular la selección de safaris y safaris de vista previa.
Si esto no funciona, consulte esta answer o post para depurarlo.
Para encontrar estos tipos de problemas de memoria y puntero en general, desea ejecutar su código contra un corrector de errores de memoria de tiempo de ejecución como Valgrind . Esto debería ser capaz de señalar muchas cosas que su código está haciendo mal, más allá de las que causan que se bloquee.
Valgrind puede trabajar en OSX (aunque dice que es "incompatible e incompleto y defectuoso"), y con un poco de piratería, alguien consiguió que funcionara en los ejecutables de iPhone SDK .
Aún mejor, puedes probar Instruments, que es parte de XCode. Hay un tutorial para ejecutarlo here .
Para mí, el problema fue resuelto por
(gdb) call (void)_CFAutoreleasePoolPrintPools()
justo después del accidente. La dirección en la parte superior de la pila era la dirección del culpable. Lanzó un retain
y voila.
La dirección que figura en el mensaje de registro no me llevó a ninguna parte. Nunca apareció en ninguno de los varios Instrumets. Aparentemente un puntero a algunos datos internos que ya habían sido liberados.
Si malloc_error_break
no está ayudando ...
La mejor forma de resolver este error es ejecutar instrumentos con los NSZombies
encendidos. Los instrumentos lo marcarán cuando se envíe un mensaje al Zombie y podrá seguir directamente hasta la línea de código.
Snow Leopard requirió, ¡qué salvavidas!
Solo quiero agregar mi experiencia además de la respuesta de Quinn Taylor.
En una de mis aplicaciones, tengo que analizar y guardar datos en objetos de datos centrales y luego obtener estos objetos para mostrarlos en las vistas. De hecho, la aplicación funciona bien y no se cuelga del todo, hasta que intenté hacer una prueba de estrés de navegar varias veces, intenté abrir varias vistas lo más rápido posible. La aplicación se bloquea con el mensaje anterior.
He intentado todos los métodos que Quinn sugirió en su respuesta y todavía no pude averiguar dónde estaba la causa exacta.
Configuré NSZombieEnabled = YES, y NSStackLogging = YES, ejecuté el comando shell malloc_history para averiguar por qué, pero todavía no tuve suerte. Siempre señala dónde guardo los datos en los objetos de datos centrales, de hecho, he verificado miles de veces los objetos liberados allí, nada extraño.
Correr en Instrumentos con varias herramientas (Asignaciones, Fugas, etc.) aún no ayudó. Habilitar a la Guardia Malloc aún no obtuvo nada.
Rescate final: intenté volver a las vistas en las que se tomaron los objetos de Core Data y envié un mensaje de retención a todos estos objetos, y tomé nota de estos cambios. ¡Solucionó el problema!
Entonces, descubrí que no pude retener uno, esa es exactamente la causa. Solo quiero compartir mi experiencia para que tengas otro rescate para tu aplicación.
Verifique sus clases y mire bajo el método dealloc. Asegúrate de llamar a [super dealloc].
Tuve exactamente este mismo problema y descubrí que estaba llamando [self dealloc]
lugar. Simplemente no prestando atención.