¿Cómo encontrar la causa de un error "doble libre" de malloc?

80

Estoy programando una aplicación en Objective-C y recibo este error:

MyApp (2121,0xb0185000) malloc: *** error para el objeto 0x1068310: doble libre
*** establece un punto de interrupción en malloc_error_break para depurar

Está sucediendo cuando lanzo un NSAutoreleasePool y no puedo averiguar qué objeto estoy lanzando dos veces.

¿Cómo establezco su punto de ruptura?

¿Hay alguna forma de saber qué es este "objeto 0x1068310"?

gonso
fuente
3
es posible que desee etiquetar esta publicación con iPhone también para obtener más personas
Benny Wong
4
Se eliminó la etiqueta "iphone" en favor de otras etiquetas más pertinentes.
Quinn Taylor
3
No puedo imaginar por qué a esta pregunta del iPhone le faltaría la etiqueta del iPhone. Debe haber más personas siguiendo "iPhone" que algunas de estas otras etiquetas como "autorelease". Si desea encontrar "liberación automática", búsquelo, no siga la etiqueta. Así que volví a poner "iPhone".
Nosredna
6
La razón por la que eliminé la etiqueta "iphone" es porque nada acerca de la pregunta es específico del iPhone. El único vínculo es que ocurre en una aplicación de iPhone, pero exactamente el mismo error puede ocurrir en cualquier aplicación C o Objective-C. No espero que las personas que siguen el iPhone estén interesadas casualmente en esto; más bien, serían las personas que buscan cosas como "doble gratis" o "malloc_error_break", y si agregan "iPhone", aún aparecerá . No discutamos sobre las etiquetas, pero consideremos que quizás las personas que responden pueden saber dónde pertenece mejor la pregunta.
Quinn Taylor
3
Esta pregunta es al menos específica de Cocoa. Si la etiqueta de iPhone es ofensiva, ¿qué tal una etiqueta de cocoa? La intención obvia se aplica a Objective-C en Cocoa en XCode. No Objective-C en Windows o Linux, o fuera del contexto de XCode.
runako

Respuestas:

38

Descubrirá cuál es el objeto cuando entre en el depurador. Simplemente busque la pila de llamadas y encontrará dónde la libera. Eso te dirá qué objeto es.

La forma más sencilla de establecer el punto de interrupción es:

  1. Vaya a Ejecutar -> Mostrar -> Puntos de interrupción ( ALT- Command- B)
  2. Desplácese hasta el final de la lista y agregue el símbolo malloc_error_break
Frank Krueger
fuente
1
Intenté eso, pero obtengo: no puedo desarmar malloc_error_break .... ¿qué significa?
gonso
3
No hay ayuda para la liberación automática doble gratis. Necesita zombis
Rog
58
@gonso - Solo por curiosidad, si esto no funcionó para usted, ¿por qué lo aceptó como la respuesta?
Quinn Taylor
8
En Xcode 4.3.2, los puntos de interrupción se pueden encontrar en Ver → Navegadores → Mostrar navegador de puntos de interrupción o ⌘6 (Cmd-6)
Andreas Ley
46

Cuando un objeto se "libera dos veces", la causa más común es que está (innecesariamente) liberando un objeto liberado automáticamente, y luego se libera automáticamente cuando se vacía el grupo de liberación automática que lo contiene.

Descubrí que la mejor manera de rastrear la versión adicional 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 me han salvado el tocino más de unas pocas veces. Sugiero consultar esta Nota técnica en developer.apple.com - enlace salta a la sección sobre el marco de Cocoa's Foundation).

Editar: a menudo puede rastrear el objeto ofensivo dentro del depurador de Xcode, pero a menudo es mucho más fácil si usa Instrumentos para ayudarlo. Desde Xcode, elija Ejecutar → Comenzar con la herramienta de rendimiento → Asignaciones de objetos y debería poder rastrear el objeto ofensivo hasta donde se creó. (Esto funcionará mejor si tienes los zombis habilitados como se mencionó anteriormente). Nota: Snow Leopard agrega una herramienta Zombies a los instrumentos, accesible también desde el menú Ejecutar. ¡Podría valer los $ 29 solo! ;-)

También hay una pregunta SO relacionada aquí .

Quinn Taylor
fuente
1
La página wiki de CocoaDev vinculada en respuesta está muerta :(
Devarshi
12

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 hacer que estos objetos se muestren en las vistas. De hecho, la aplicación funciona bien y no se bloquea en absoluto, hasta que intenté hacer una prueba de esfuerzo de navegar de un lado a otro varias veces, intenté abrir varias vistas lo más rápido posible. La aplicación se bloquea con el mensaje anterior.

Probé todos los métodos que sugirió Quinn en su respuesta y aún 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 aún así no tuve suerte. Siempre señala dónde guardo los datos en objetos de datos centrales, de hecho, he verificado miles de veces los objetos liberados allí, nada extraño.

Ejecutar instrumentos con varias herramientas (asignaciones, fugas, etc.) todavía no ayudó. Habilitar al guardia Malloc todavía no tiene nada.

Rescate final: traté de volver a las vistas donde los objetos se tomaron de Core Data y envié un mensaje de retención a todos estos objetos, y tomé nota de estos cambios. ¡¡¡Resolvió 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.

Hoang Pham
fuente
9

Abra la consola del depurador presionando Cmd + Shift + R. Allí, escriba

break malloc_error_break

para establecer un punto de interrupción al comienzo de la malloc_error_breakfunción.

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, debe hacer esto mientras el objeto aún está vivo; si el objeto ya se ha liberado cuando lo hace, entonces esto no funcionará.

Adam Rosenfield
fuente
Esta es la liberación automática, necesita Zombies.
Rog
1
Finalmente lo que hice fue invocar el método "sospechoso" fuera de AutoreleasePoll. Es curioso pensar que todavía recibí la advertencia, pero no se alcanzó ningún punto de quiebre. Solo comenté bloques hasta que encontré la línea. Estaba liberando automáticamente una cadena que se creó con stringWithFormat (sin asignación ni copia). ¡Gracias a todos por sus consejos! Gonso
gonso
Para este tipo particular de error, romper malloc_error_break nunca ha ayudado a encontrar el problema; siempre ha requerido habilitar zombies.
Quinn Taylor
Consulte aquí para obtener instrucciones sobre cómo establecer un punto de interrupción para malloc_error_break en XCode 4: stackoverflow.com/questions/6969407/…
benvolioT
1
@Zammbi: Intente usar el poalias, o de manera equivalente expr -o. En los años transcurridos desde que se escribió originalmente esta respuesta, el motor de depuración utilizado por Xcode se ha cambiado de GDB a LLDB, y LLDB tiene un conjunto diferente de comandos.
Adam Rosenfield
4

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 retainy listo.

La dirección proporcionada en el mensaje de registro no me llevó a ninguna parte. Nunca apareció en ninguno de los diversos Instrumets. Al parecer, un puntero a algunos datos internos que ya se habían liberado.

c-alpha
fuente
4

Agregar un punto de interrupción simbólico en Xcode 4

Solo una actualización para que esto sea relevante para Xcode 4 ...

De la Guía del usuario de Xcode 4 :

Para agregar un punto de interrupción simbólico. . .

  1. En la esquina inferior izquierda del navegador de puntos de interrupción, haga clic en el botón Agregar.
  2. Elija Agregar punto de interrupción simbólico.
  3. Ingrese el nombre del símbolo en el campo Símbolo.
  4. Haz clic en Listo.
Viejo McStopher
fuente
2

Verifique sus clases y busque en el método dealloc. Asegúrate de que te importa llamar[super dealloc].

Tuve exactamente el mismo problema y descubrí que estaba llamando [self dealloc]. Simplemente sin prestar atención.

Wes Duff
fuente
2

Encuentre los pasos a continuación sobre cómo encontrar el objeto que está libre y bloquear la aplicación.

1) Haga clic en el " navegador de puntos de interrupción ".
2) Luego haga clic en el botón " + " que se encuentra debajo.
3) Agregue el " Punto de interrupción 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 presentación GIF a continuación.

Representación GIF

Ramkrishna Sharma
fuente
1

Esto suele ser causado por algún inspector, como safari o vista previa de safari. Consulte la publicación o publicación y pregunta .

Elimine la selección de Mostrar Web automáticamente ...., eliminará este problema.

Tenga en cuenta que simplemente cerrar safari o la vista previa de safari no eliminará este problema. Y debe deseleccionar tanto la vista previa de safari como la de safari.

Si esto no funciona, consulte esta respuesta o publique para depurarlo.

deseleccionar inspeccionar automáticamente en la vista previa de safari

LF00
fuente
0

En Xcode, haga clic a la izquierda del número de línea para establecer un punto de interrupción. Luego, puede iniciarlo haciendo un "Compilar y depurar".

Se recomienda no tener ningún objeto que cree, autoreleaseya que la memoria es una mercancía en el iPhone. Apple recomienda llamar explícitamente release.

Benny Wong
fuente
0

Para encontrar este tipo de problemas de memoria y puntero en general, desea ejecutar su código contra un verificador de errores de memoria en tiempo de ejecución como Valgrind . Esto debería poder señalar muchas cosas que su código está haciendo mal, más allá de las que causan que se bloquee.

Valgrind puede funcionar en OSX (aunque dice que "no es compatible, está incompleto y tiene errores"), y con un poco de pirateo, alguien hizo que funcionara en los ejecutables del SDK de iPhone .

Aún mejor, puede probar Instruments, que es parte de XCode. Hay un tutorial para ejecutarlo aquí .

Jared Oberhaus
fuente
1
instrumentos es el camino a seguir; usa el instrumento de asignación de objetos y enciende a los zombis. (o simplemente usa la plantilla de Zombies). Valgrind es una solución de último recurso. Es terriblemente lento y, a menudo, simplemente no funciona.
bbum
0

Si malloc_error_breakno está ayudando ...

La mejor forma de solucionar este error es ejecutar los instrumentos con el NSZombiesencendido. Los instrumentos te avisarán cuando se envíe un mensaje al Zombie y podrás rastrear directamente la línea de código.

Snow Leopard requiere, ¡qué salvavidas!

iOSDevSF
fuente