wake-up-neo.net

iPhone-Entwicklung: Der freigegebene Zeiger wurde nicht zugewiesen

ich habe diese Nachricht vom Debugger erhalten:

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

also habe ich ein bisschen nachgezeichnet und bekam:

(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

und ich kann wirklich nicht verstehen, was ich falsch mache. Hier ist der Code der Funktion [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;
}

die andere zuvor aufgerufene benutzerdefinierte Funktion ist die folgende:

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

Ich hatte das gleiche Problem mit vielen gleichen Symptomen:

  • zeiger, der freigegeben wird, wurde Fehler nicht zugewiesen
  • auf Xcode 3.2 aktualisiert
  • fehler im Code für Bilder

Wenn ich das Build-Ziel auf 3.1 ändere, verschwinden die Fehler im Simulator. Wenn ich den Code auf dem Gerät ausführe, werden die Fehler nicht angezeigt. Möglicherweise ein Bug in 3.0

Mein Rat ist, mit 3.1 als Ziel zu testen, und wenn Sie möchten, können Sie für die Veröffentlichung 3.0 erstellen und sich keine Sorgen über die Fehler machen, da diese auf dem Gerät nicht auftreten.

27
nevan king

Es sieht so aus, als ob Sie einen beschädigten Speicherfehler haben, der wahrscheinlich nicht in diesem Code enthalten ist. Beschädigte Speicherbugs sind meine zweitspaßigsten Bugs, zum Teil, weil sie oft nicht deterministisch sind und die Symptome (auch Abstürze genannt) normalerweise lange nach auftreten.

Es gibt zwei Haupttypen von Speicherfehlern:

  1. Zuteilen von mehr als Sie frei.
  2. Geben Sie mehr frei, als Sie zuteilen.

In diesem Fall scheint es, als ob Sie zu viel Zeit haben. Dies ist der leichtere Fall (b/c kann früher abstürzen), aber der schwierigere, ihn zu finden.

Hier ist eine Strategie, die Sie verwenden können, um zusätzliche Aufhebungen zu finden:

  • Deaktivieren Sie einige Ihrer Freigabe.
  • Überprüfen Sie, ob der Absturz weiterhin auftritt.

Im Idealfall finden Sie einen einzigen Befehl zum Aufheben der Zuweisung, mit dem Ihr Code nach dem Entfernen ordnungsgemäß funktioniert. Es kann nützlich sein, einen binären Suchansatz zu verwenden, wenn dies für Ihre Codebasis sinnvoll ist. Wenn es sich um eine große Codebasis handelt, verwenden Sie hoffentlich die Versionskontrolle und können versuchen, sich auf die neuesten Unterschiede zu konzentrieren.

Beachten Sie, dass die Freigabe auf verschiedene Arten hier aufgerufen werden kann. Höchstwahrscheinlich rufen Sie release und autorelease für Objekte auf. Es ist auch möglich, dass Sie explizit dealloc aufrufen (was jedoch normalerweise ein Fehler ist). Und natürlich können Sie auch explizit free direkt aufrufen.

Sobald Sie die zusätzlichen Zuordnungen beseitigt haben, ist es eine gute Idee, auch nach Speicherlecks (auch als zusätzliche Zuordnungen bezeichnet) zu suchen. Sie können dazu Instrumente und andere Werkzeuge verwenden. Ein guter Anfang ist das Lesen von Auffinden von Speicherlecks im iPhone-Entwicklungshandbuch.

Hinzugefügt: Es ist auch eine gute Idee, einen Zeiger auf nil zu setzen, unmittelbar nachdem Sie ihn freigegeben und damit fertig sind. Auf diese Weise führt ein späterer Aufruf von [objectPtr release]; zu nichts.

(PS Übrigens, mein am meisten Spaß machender Fehlertyp ist die Speicherbeschädigung in Multithread-Code. Ich hatte einen davon einmal in einer Multimillionen-Zeilencodebasis.)

22
Tyler

Wahrscheinlich ist dies nicht die Ursache für Ihren Absturz, aber Sie verlieren Speicher, indem Sie die Core Foundation-Objekte context2, unmasked und mask nicht mithilfe von CFRelease(), CFImageRelease() oder dergleichen freigeben.

3
Brad Larson

Ich hatte das gleiche Problem mit dem folgenden Code.

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

Ich habe die Funktion von der Open Source Twitterfon App übernommen.

Als ich versuchte, das Problem zu beheben, habe ich versucht, die letzte Zeile in zu ändern

self.imageView.image = [converted retain]

Und das stoppte die Fehlermeldungen in der Konsole. Ich werde das in Kürze in Leaks nachprüfen, um zu sehen, was passiert.

0
infiniteloop

Ich habe mit dem gleichen Fehler in meinem Code zu kämpfen. Was mich verwundert hat, ist, dass meine App unter OS 3.0 problemlos funktioniert hat, bis ich eine geringfügige Änderung an einem Code vorgenommen habe, der nichts mit CGImage * zu tun hat. Aber wenn es einmal versagt hat, hat es nie ohne Absturz funktioniert. Als ich auf 3.1 umgestiegen bin, hat alles wieder funktioniert. Ich habe den Fehler auf einen Aufruf von CGImageRelease () eingegrenzt. Entweder das Entfernen dieser Zeile oder das Hinzufügen einer Beibehaltung für das resultierende UIImage löste das Problem - obwohl dies keine Lösung ist, da die App Speicherlecks verursachen wird.

Ich habe versucht, NSZombie mit Instrumenten zu benutzen. Das hat nicht geholfen - die App ist abgestürzt, ohne dass Zombies erkannt wurden.

Darüber hinaus stürzen Apples eigene Beispiel-Apps (wie TheElements) NICHT ab, sondern verwenden denselben EXAKTEN Code wie meine App. Ich kämpfe also darum, das Problem zu akzeptieren, das in den Frameworks liegt. Im Moment wechsle ich zu 3.1 und gehe weiter.

0
Ephraim

Ich wollte nur noch einmal bestätigen, dass ich Folgendes bekommen hatte:

Zeiger freigegeben wurde nicht zugeordnet

fehler und es ging weg, wenn ich mein Ziel OS zu 3.1 im Gegensatz zu 3.0 ändere

0
mracoker

Es könnte nur ich sein, aber Sie können das Folgende nicht tun?

UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return whiteMasked;

whiteMasked wird auf dem Stapel der Funktion zugewiesen und nach der Rückkehr ist der Zeiger nicht mehr gültig? Oder fehlt mir etwas? Wenn Sie das zurückgegebene UIImage * verwenden, kann nicht garantiert werden, dass es noch vorhanden ist. (Es wäre ein Hit und Miss). Müssen Sie ein UIImage * nicht zuweisen und dann automatisch freigeben, bevor Sie zurückkehren?

0
dkardell