2009-09-14 5 views
19

me dieron este mensaje desde el depurador:iPhone desarrollo: puntero siendo liberado no fue asignado

Pixture(1257,0xa0610500) malloc: *** error for object 0x21a8000: pointer being freed was not allocated 
*** set a breakpoint in malloc_error_break to debug 

así que hice un poco de rastreo y tengo:

(gdb) shell malloc_history 1257 0x21a8000

ALLOC 0x2196a00-0x21a89ff [size=73728]: thread_a0610500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerDisplayIfNeeded | -[CALayer _display] | CABackingStoreUpdate | backing_callback(CGContext*, void*) | -[CALayer drawInContext:] | -[UIView(CALayerDelegate) drawLayer:inContext:] | -[AvatarView drawRect:] | -[AvatarView overlayPNG:] | +[UIImageUtility createMaskOf:] | UIGraphicsGetImageFromCurrentImageContext | CGBitmapContextCreateImage | create_bitmap_data_provider | malloc | malloc_zone_malloc

y realmente no puedo entender WH en que estoy haciendo mal. Aquí está el código de la función [UIImageUtility createMaskOf:]:

+ (UIImage *)createMaskOf:(UIImage *)source { 
    CGRect rect = CGRectMake(0, 0, source.size.width, source.size.height); 
    UIGraphicsBeginImageContext(CGSizeMake(source.size.width, source.size.height)); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGContextTranslateCTM(context, 0, source.size.height); 
    CGContextScaleCTM(context, 1.0, -1.0); 

    UIImage *original = [self createGrayCopy:source]; 

    CGContextRef context2 = CGBitmapContextCreate(NULL, source.size.width, source.size.height, 8, 4 * source.size.width, 
                CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipLast); 
    CGContextDrawImage(context2, CGRectMake(0, 0, source.size.width, source.size.height), original.CGImage); 
    CGImageRef unmasked = CGBitmapContextCreateImage(context2); 

    const float myMaskingColorsFrameColor[6] = { 1,256,1,256,1,256 }; 
    CGImageRef mask = CGImageCreateWithMaskingColors(unmasked, myMaskingColorsFrameColor); 

    CGContextSetRGBFillColor (context, 256,256,256, 1); 
    CGContextFillRect(context, rect); 
    CGContextDrawImage(context, rect, mask); 

    UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return whiteMasked; 
} 

la otra función personalizada llamada antes de eso es la siguiente:

- (UIImage *)overlayPNG:(SinglePart *)sp { 
    NSLog([sp description]); 
    // Rect and context setup 
    CGRect rect = CGRectMake(0, 0, sp.image.size.width, sp.image.size.height); 
    NSLog(@"%f x %f", sp.image.size.width, sp.image.size.height); 

    // Create an image of a color filled rectangle 
    UIImage *baseColor = nil; 
    if (sp.hasOwnColor) { 
      baseColor = [UIImageUtility imageWithRect:rect ofColor:sp.color]; 
    } else { 
     SinglePart *facePart = [editingAvatar.face.partList objectAtIndex:0]; 
     baseColor = [UIImageUtility imageWithRect:rect ofColor:facePart.color]; 
    } 

    // Crete the mask of the layer 
    UIImage *mask = [UIImageUtility createMaskOf:sp.image]; 
    mask = [UIImageUtility createGrayCopy:mask]; 

    // Create a new context for merging the overlay and a mask of the layer 
    UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height)); 
    CGContextRef context2 = UIGraphicsGetCurrentContext(); 

    // Adjust the coordinate system so that the origin 
    // is in the lower left corner of the view and the 
    // y axis points up 
    CGContextTranslateCTM(context2, 0, sp.image.size.height); 
    CGContextScaleCTM(context2, 1.0, -1.0); 

    // Create masked overlay color layer 
    CGImageRef MaskedImage = CGImageCreateWithMask (baseColor.CGImage, mask.CGImage); 

    // Draw the base color layer 
    CGContextDrawImage(context2, rect, MaskedImage); 

    // Get the result of the masking 
    UIImage* overlayMasked = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height)); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // Adjust the coordinate system so that the origin 
    // is in the lower left corner of the view and the 
    // y axis points up 
    CGContextTranslateCTM(context, 0, sp.image.size.height); 
    CGContextScaleCTM(context, 1.0, -1.0); 

    // Get the result of the blending of the masked overlay and the base image 
    CGContextDrawImage(context, rect, overlayMasked.CGImage); 

    // Set the blend mode for the next drawn image 
    CGContextSetBlendMode(context, kCGBlendModeOverlay); 

    // Component image drawn 
    CGContextDrawImage(context, rect, sp.image.CGImage); 

    UIImage* blendedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    CGImageRelease(MaskedImage); 

    return blendedImage; 
} 

Respuesta

27

que he tenido el mismo problema, con muchos de los mismos síntomas:

  • puntero siendo liberado no fue asignado el error
  • actualizado a Xcode 3.2
  • error que tuvo lugar en el código de imágenes

Si cambio el objetivo de compilación a 3.1, los errores en el simulador desaparecen. Si ejecuto el código en el dispositivo, los errores no aparecen. Posiblemente un error en 3.0

Mi consejo es probar con 3.1 como su objetivo, y si lo desea, puede compilar para 3.0 la versión y no preocuparse por los errores, ya que no ocurren en el dispositivo.

+0

Parece un error en 3.0, ya que también tuve este problema y desapareció cuando configuré el objetivo en 3.1. – lucius

+0

Solo para decir que tenía exactamente el mismo problema, y ​​la configuración 3.1 también se resolvió en mi caso. Gracias – Andy

+0

Otro "yo también". Parece un error en el simulador 3.0 específicamente. Las pruebas en 3.1+ en el simulador y 3.0 en el dispositivo son buenas. –

22

Parece que tiene un error de memoria dañada, y es probable que no en este código. errores de memoria dañada son mis segundos errores más divertido, en parte porque a menudo son no determinista, y los síntomas (también conocidos como los accidentes suelen ocurrir) mucho después de que el fallo éxito real.

Hay dos tipos principales de errores de memoria:

  1. dediquen más libres.
  2. Liberar más de asignar.

En este caso, parece que está liberando demasiado, que es el caso más fácil de ver (b/c puede fallar antes) pero es más difícil de rastrear.

Aquí es una estrategia que puede utilizar para ayudar a encontrar un cancelaciones de asignación adicionales:

  • desactivar algunas de sus cancelaciones de asignación.
  • Vea si el bloqueo todavía se produce.

Idealmente, puede encontrar un solo comando de desasignación que, cuando se elimine, permitirá que su código funcione correctamente. Podría ser útil probar un enfoque de búsqueda binaria, si eso es práctico para su base de código. Si se trata de una gran base de código, con suerte está utilizando el control de versiones y puede intentar centrarse en las diferencias recientes.

Tenga en cuenta que se pueden invocar cancelaciones de asignación de varias maneras diferentes aquí. Lo más probable es que llame a release y autorelease en objetos. También es posible que esté llamando explícitamente al dealloc (aunque esto suele ser un error). Y, por supuesto, incluso podría llamar explícitamente al free directamente.

Una vez que haya librado de las cancelaciones de asignación extra, es una buena idea para comprobar también que no haya fugas de memoria (también conocido como asignaciones adicionales). Puedes hacer esto usando instrumentos y otras herramientas. Un buen lugar para comenzar es leyendo Finding Memory Leaks en la guía de desarrollo de iPhone.

Agregado: También es una buena idea establecer un puntero a nil inmediatamente después de haberlo liberado y de haberlo utilizado.De esta manera, si llama al [objectPtr release]; más tarde, no hará nada.

(PS Por cierto, mi # 1 más divertido tipo de errores es una corrupción de memoria en el código de mutlithreaded. Tenía uno de esos una vez en una base de código de línea de varios millones.)

+0

Lo que dices es probablemente cierto, también porque este mensaje que publiqué no corresponde a bloqueos de aplicaciones, simplemente escribe en la consola de depuración (y ralentiza la aplicación) en un fashon aleatorio, a veces me da 2 de ellos, a veces 4, a veces mucho, a veces ni siquiera mensajes ... De todos modos, trataré de seguir sus instrucciones y ver si puedo llegar a algún lado. Si no lo hago, ¿puedo publicar un poco más de código y me pueden ayudar a encontrar el problema? – w4nderlust

+0

Puede publicar, pero no hay promesas sobre la depuración detallada línea por línea aquí. Stackoverflow se trata más de preguntas de gran formato o preguntas rápidas pero específicas, en lugar de preguntas que requieren mucho tiempo y detalles, ya que este último tipo es el menos útil para otras personas. También es mucho trabajo por hacer para un extraño de forma gratuita;) – Tyler

+0

Eliminé cada llamada de lanzamiento en todas las clases que se cargan antes de que salga el primero de esos mensajes. No obtuve ningún resultado en absoluto. Te mostraré la función anterior llamando a la que he mostrado, esperando que el problema esté allí. (Por cierto tengo que decir algo gracioso: la aplicación no ha tenido este error ya que actualicé a Snow Leopard y xcode 3.2 ... sin cambiar una línea salió este erorr) – w4nderlust

3

Aunque probablemente no sea la causa de su bloqueo, está perdiendo memoria al no liberar los objetos context2, unmasked y mask Core Foundation utilizando CFRelease(), CFImageRelease() o similares.

+0

Se agregó CGContextRelease() y CGImageRelease(), gracias por la sugerencia;) – w4nderlust

0

Tuve el mismo problema con el siguiente código.

-(void)adjustImageToImageView:(UIImage*)img{ 

float numPixels = 100; 
float radius = 5; 
UIGraphicsBeginImageContext(CGSizeMake(numPixels, numPixels)); 
CGContextRef c = UIGraphicsGetCurrentContext(); 

CGContextBeginPath(c); 
CGContextMoveToPoint (c, numPixels, numPixels/2); 
CGContextAddArcToPoint(c, numPixels, numPixels, numPixels/2, numPixels, radius); 
CGContextAddArcToPoint(c, 0,   numPixels, 0,   numPixels/2, radius); 
CGContextAddArcToPoint(c, 0,   0,   numPixels/2, 0,   radius); 
CGContextAddArcToPoint(c, numPixels, 0,   numPixels, numPixels/2, radius); 
CGContextClosePath(c); 

CGContextClip(c); 

[img drawAtPoint:CGPointZero]; 
UIImage *converted = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
self.imageView.image = converted; } 

Tomé la función desde la aplicación de código abierto Twitterfon.

Cuando yo estaba tratando de solucionar el problema, he intentado cambiar la última línea de

self.imageView.image = [converted retain] 

Y eso se detuvieron los mensajes de error en la consola. Voy a verificar esto en Leaks pronto para ver qué está pasando.

+0

Acabo de ejecutar Leaks. La aplicación está filtrando el UIImage. ¡Así que definitivamente esta no es una solución! Es interesante que los errores de Malloc fueron suprimidos por esto sin embargo. – infiniteloop

0

Sólo quería confirmar, una vez más, que había estaba recibiendo:

puntero de ser liberado no fue asignado el error

y se fue si cambio de sistema operativo de destino para 3.1 en comparación con 3.0

+0

Sí, lo mismo para mí. 'UIGraphicsGetImageFromCurrentImageContext()' se supone que devuelve un UIImage liberado automáticamente, pero parece que se está duplicando automáticamente, SÓLO en el simulador 3.0 y SÓLO con Xcode 3.2 –

0

He tenido problemas con el mismo error en mi código. Lo que me dejó perplejo es que mi aplicación funcionó en OS 3.0 sin ningún problema hasta que hice una pequeña modificación en un código que no tiene nada que ver con las cosas de CGImage *. Pero una vez que comenzó a fallar, nunca funcionó sin fallar. Cuando cambié a 3.1, todo funcionó de nuevo. Reduje el error a una llamada CGImageRelease(). Eliminar la línea o agregar un retener en el UIImage resultante resolvió el problema, aunque no es una solución, ya que la aplicación tendrá pérdidas de memoria.

Intenté usar NSZombie con instrumentos. Esto no ayudó: la aplicación se bloqueó sin que se detectaran zombies.

Además, las propias aplicaciones de ejemplo de Apple (como TheElements) NO se cuelgan pero usan el mismo código EXACTO que mi aplicación. Por lo tanto, estoy luchando para aceptar que el problema radica en los Frameworks. Por ahora, estoy cambiando a 3.1 y sigo adelante.

0

¿Podría ser solo yo pero no puedes hacer lo siguiente?

UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext(); 

UIGraphicsEndImageContext(); 

return whiteMasked; 

whiteMasked se asigna en la pila de la función y después devuelve el puntero ya no es válida? ¿O me estoy perdiendo algo? Si usas el UIImage * devuelto, no está garantizado que aún esté allí. (sería un al azar). ¿No necesita asignar un UIImage * y luego volver a soltarlo antes de volver?

+0

Los objetos en Cocoa/Objective-C siempre se asignan en el montón, nunca en la pila. El puntero almacenado en 'whiteMasked' es válido al menos hasta que se vacíe el grupo de autorrelease actual, que no será hasta el final del ciclo de evento. Está bien ser utilizado en esta función y está bien devolverlo también. Solo necesitaríamos hacer una copia si planeamos guardarla y usar la misma imagen más tarde (por ejemplo, en una variable de instancia). – benzado

Cuestiones relacionadas