iPhone开发:没有分配被释放的指针

w4n*_*ust 19 iphone memory-leaks memory-management objective-c

我从调试器得到这条消息:

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

所以我做了一些跟踪并得到了:

(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

而我真的无法理解我做错了什么.这是[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;
}
Run Code Online (Sandbox Code Playgroud)

之前调用的另一个自定义函数如下:

- (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;
}
Run Code Online (Sandbox Code Playgroud)

nev*_*ing 27

我有同样的问题,有很多相同的症状:

  • 被释放的指针没有分配错误
  • 升级到Xcode 3.2
  • 图像代码中发生错误

如果我将构建目标更改为3.1,模拟器中的错误就会消失.如果我在设备上运行代码,则不会出现错误.可能是3.0中的错误

我的建议是以3.1为目标进行测试,如果需要,可以为3.0版本进行构建,而不用担心错误,因为它们不会在设备上发生.


Tyl*_*ler 22

看起来你有一个损坏的内存错误,它可能不在这个代码中.损坏的内存错误是我第二个最有趣的错误,部分原因是它们通常是非确定性的,并且症状(即崩溃)通常在实际错误发生后很久就会发生.

有两种主要类型的内存错误:

  1. 分配比你更自由的东西.
  2. 释放超过你分配.

在这种情况下,它看起来像你正在释放太多,这是更容易看到的情况(b/c它可以提前崩溃),但更难追查.

您可以使用以下策略来帮助查找额外的解除分配:

  • 关闭一些解除分配.
  • 看看崩溃是否仍然发生.

理想情况下,您可以找到一个单独的释放命令,删除后,将允许您的代码正常工作.如果这对您的代码库很实用,那么尝试使用二进制搜索方法可能会很有用.如果它是一个很大的代码库,希望你使用版本控制,你可以尝试专注于最近的差异.

请记住,这里可以通过几种不同的方式调用解除分配.最有可能的,你打电话releaseautorelease对象上.您也可能明确地调用dealloc(但这通常是一个错误).当然,你甚至可以free直接明确地打电话.

一旦你摆脱了额外的解除分配,最好还要检查内存泄漏(也就是额外的分配).您可以使用Instruments和其他工具完成此操作.一个好的起点是阅读iPhone开发指南中的Finding Memory Leaks.

补充:nil在你发布指针并使用指针完成后立即设置指针也是一个好主意.这样,如果你[objectPtr release];稍后打电话,它将不会做任何事情.

(PS顺便说一下,我最有趣的错误类型是多线程代码中的内存损坏.我有一个曾经在数百万行代码库中.)