Sviluppo iPhone: il puntatore liberato non è stato allocato

ho ricevuto questo messaggio dal debugger:

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

quindi ho fatto un po ‘di tracciamento e ho ottenuto:

(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

e davvero non riesco a capire cosa sto sbagliando. ecco il codice della funzione [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; } 

l’altra funzione personalizzata chiamata prima è la seguente:

 - (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(@"%fx %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; } 

Ho avuto lo stesso problema, con molti degli stessi sintomi:

  • il puntatore che veniva liberato non era un errore assegnato
  • aggiornato a Xcode 3.2
  • errore che si verifica nel codice per le immagini

Se cambio il target di build su 3.1, gli errori nel simulatore spariscono. Se eseguo il codice sul dispositivo, gli errori non vengono visualizzati. Forse un bug in 3.0

Il mio consiglio è di testare 3.1 come target e, se lo si desidera, è ansible creare 3.0 per il rilascio e non preoccuparsi degli errori poiché non si verificano sul dispositivo.

Sembra che tu abbia un bug di memoria corrotto, e probabilmente non è in questo codice. I bug di memoria corrotte sono i miei secondi bug più divertenti, in parte perché sono spesso non deterministici e i sintomi (noti anche come arresti anomali) di solito avvengono molto tempo dopo l’effettivo baco.

Esistono due tipi principali di bug di memoria:

  1. Allocare più di te gratis.
  2. Liberare più di quanto stanziate.

In questo caso sembra che tu stia liberando troppo, il che è il caso più facile da vedere (b / c può bloccarsi prima) ma è più difficile rintracciare.

Ecco una strategia che puoi utilizzare per trovare ulteriori deallocations:

  • Distriggers alcuni dei tuoi deallocations.
  • Verifica se si verifica ancora l’arresto anomalo.

Idealmente, puoi trovare un unico comando di deallocazione che, una volta rimosso, permetterà al tuo codice di funzionare correttamente. Potrebbe essere utile provare un approccio di ricerca binaria, se questo è pratico per il tuo codebase. Se si tratta di una base di codice di grandi dimensioni, si spera che si stia utilizzando il controllo della versione e si possa provare a concentrarsi sulle differenze recenti.

Tieni presente che le deallocazioni possono essere invocate in diversi modi qui. Molto probabilmente, stai chiamando release e autorelease sugli oggetti. È anche ansible che tu stia chiamando esplicitamente dealloc (che di solito è un errore, però). E naturalmente potresti anche chiamare esplicitamente free direttamente.

Una volta che ti sei sbarazzato delle ulteriori deallocations, è una buona idea controllare anche le perdite di memoria (alias allocazioni extra). Puoi farlo usando strumenti e altri strumenti. Un buon punto di partenza è leggere Finding Memory Leaks nella guida allo sviluppo di iPhone.

Aggiunto: È anche una buona idea impostare un puntatore su nil subito dopo averlo rilasciato e aver finito di usarlo. In questo modo, se chiami [objectPtr release]; dopo, non farà nulla.

(PS Btw, il mio tipo di bug più divertente numero 1 è la corruzione della memoria in codice con codice mutlithed.Ho avuto uno di quelli una volta in una base di codice di linea multi-milioni.)

Anche se probabilmente non è la causa del crash, stai perdendo memoria non rilasciando il context2 , unmasked mask e mask oggetti di Core Foundation usando CFRelease() , CFImageRelease() o simili.

Ho avuto lo stesso problema con il seguente codice.

 -(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; } 

Ho preso la funzione dall’app Twitterfon open source.

Quando stavo cercando di risolvere il problema, ho provato a cambiare l’ultima riga

 self.imageView.image = [converted retain] 

E questo ha fermato i messaggi di errore nella console. Vado a controllare questo a Leaks presto per vedere cosa sta succedendo.

Volevo solo confermare, ancora una volta, che stavo ottenendo:

il puntatore liberato non è stato assegnato

errore e se ne andò se avessi cambiato il mio target su 3.1 rispetto a 3.0

Ho lottato con lo stesso errore nel mio codice. Quello che mi ha lasciato perplesso è che la mia app ha funzionato in OS 3.0 senza problemi finché non ho apportato una piccola modifica a un codice che non ha nulla a che fare con la roba di CGImage *. Ma una volta iniziato a fallire, non ha mai funzionato senza crash. Quando sono passato a 3.1, tutto ha funzionato di nuovo. Ho ristretto l’errore a una chiamata CGImageRelease (). O rimuovere la linea o aggiungere un retain sulla UIImage risultante ha risolto il problema, anche se questa non è una soluzione poiché l’app perde memoria.

Ho provato a usare NSZombie con gli strumenti. Questo non ha aiutato – l’app si è bloccata senza che venissero rilevati degli zombi.

Inoltre, le app di esempio di Apple (come TheElements) NON si bloccano ma utilizzano lo stesso codice ESATTO della mia app. Quindi, sto faticando ad accettare che il problema sia nei Framework. Per ora, sto passando a 3.1 e andando avanti.

Potrebbe essere solo io ma non puoi fare quanto segue?

 UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return whiteMasked; 

whiteMasked è allocato nello stack della funzione e dopo il suo ritorno il puntatore non è più valido? O mi sta sfuggendo qualcosa? Se usi UIImage * restituito, non è garantito che ci sia ancora. (Sarebbe un errore). Non è necessario assegnare un UIImage * e quindi autorizzarlo automaticamente prima di tornare?