【问题标题】:iPhone development: pointer being freed was not allocatediPhone开发:被释放的指针未被分配
【发布时间】:2010-11-28 07:04:39
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

    标签: iphone objective-c memory-management memory-leaks


    【解决方案1】:

    可能只有我,但您不能执行以下操作?

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

    whiteMasked 分配在函数的栈上,返回后指针不再有效?还是我错过了什么?如果您使用返回的 UIImage* 它不能保证仍然存在。 (这将是一个打击和错过)。你不需要分配一个 UIImage* 然后在返回之前自动释放它吗?

    【讨论】:

    • Cocoa/Objective-C 中的对象总是在堆上分配,而不是在栈上。存储在whiteMasked 中的指针至少在当前自动释放池耗尽之前有效,直到事件循环结束。在这个函数中使用很好,返回也很好。如果我们计划保存它并稍后使用相同的图像(例如,在实例变量中),我们只需要制作一个副本。
    【解决方案2】:

    我在代码中遇到了同样的错误。我感到困惑的是,我的应用程序在 OS 3.0 中运行没有任何问题,直到我对与 CGImage* 内容无关的代码进行了小幅修改。但是一旦它开始失败,它就永远不会崩溃。当我切换到 3.1 时,一切都恢复了。我将错误缩小到 CGImageRelease() 调用。删除该行或在生成的 UIImage 上添加保留解决了问题 - 尽管这是一个没有解决方案,因为应用程序将泄漏内存。

    我尝试将 NSZombie 与乐器一起使用。这无济于事——应用程序在没有检测到任何僵尸的情况下崩溃了。

    此外,Apple 自己的示例应用程序(如 TheElements)不会崩溃,而是使用与我的应用程序相同的 EXACT 代码。所以,我很难接受问题在于框架。现在,我正在切换到 3.1 并继续前进。

    【讨论】:

      【解决方案3】:

      我只是想再次确认一下,我得到的是:

      被释放的指针未被分配

      如果我将目标操作系统更改为 3.1 而不是 3.0,它就会消失

      【讨论】:

      • 是的,我也一样。 UIGraphicsGetImageFromCurrentImageContext() 应该返回一个自动释放的 UIImage,但它似乎是双重自动释放它,只在 3.0 模拟器和 Xcode 3.2 中
      【解决方案4】:

      我也遇到过同样的问题,有很多相同的症状:

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

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

      我的建议是使用 3.1 作为您的目标进行测试,如果您愿意,您可以构建 3.0 以供发布,而不必担心错误,因为它们不会在设备上发生。

      【讨论】:

      • 它看起来像 3.0 中的一个错误,因为我也遇到了这个问题,当我将目标设置为 3.1 时它就消失了。
      • 只是说我遇到了完全相同的问题,并且在我的情况下设置 3.1 也解决了。谢谢
      • 另一个“我也是”。看起来像是 3.0 模拟器中的一个错误。在模拟器中测试 3.1+ 和在设备上测试 3.0 都很好。
      【解决方案5】:

      我在下面的代码中遇到了同样的问题。

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

      我从开源 Twitterfon 应用程序中获取了该功能。

      当我尝试解决问题时,我尝试将最后一行更改为

      self.imageView.image = [converted retain]
      

      这停止了控制台中的错误消息。我将很快在 Leaks 中查看这一点,看看发生了什么。

      【讨论】:

      • 我刚刚运行了 Leaks。该应用程序正在泄漏 UIImage。所以这绝对不是解决方案!有趣的是,malloc 错误被此抑制了。
      【解决方案6】:

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

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

      1. 分配的比免费的多​​。
      2. 释放的比分配的多。

      在这种情况下,您似乎释放了太多东西,这是更容易看到的情况(b/c 它可能会更早崩溃)但更难追踪。

      您可以使用以下策略来帮助找到额外的释放:

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

      理想情况下,您可以找到一个解除分配命令,删除该命令后,您的代码就可以正常工作。如果对您的代码库实用,尝试二进制搜索方法可能会很有用。如果它是一个大型代码库,希望您正在使用版本控制,并且您可以尝试关注最近的差异。

      请记住,此处可以通过多种不同方式调用解除分配。最有可能的是,您在对象上调用 releaseautorelease。您也有可能明确调用dealloc(不过这通常是一个错误)。当然,您甚至可以直接显式调用free

      一旦您摆脱了额外的释放,最好同时检查内存泄漏(也称为额外分配)。您可以使用 Instruments 和其他工具来做到这一点。一个好的起点是阅读 iPhone 开发指南中的Finding Memory Leaks

      补充:在您发布并使用完它之后立即设置指向nil 的指针也是一个好主意。这样,如果你稍后再调用[objectPtr release];,它就不会做任何事情。

      (顺便说一句,我 #1 最有趣的错误类型是多线程代码中的内存损坏。我曾经在数百万行代码库中遇到过这样的错误。)

      【讨论】:

      • 它你说的可能是真的,也因为我发布的这条消息与应用程序崩溃不对应,它只是以随机方式写入调试控制台(并减慢应用程序),有时它给出我其中 2 个,有时 4 个,有时很多,有时甚至没有消息...无论如何,我会尝试按照您的指示进行操作,看看我是否可以到达任何地方。如果我没有,也许我可以发布更多代码,您可以帮助我找到问题吗?
      • 你可以发帖,但这里没有详细的逐行调试的承诺。 Stackoverflow 更多的是关于全局问题或快速但具体的问题,而不是耗时和详细的问题,因为最后一种对其他人最没用。此外,免费为陌生人做很多工作;)
      • 我删除了在第一条消息出来之前加载的所有类中的每个发布调用。我根本没有结果。我将向您展示上一个调用我展示的函数的函数,希望问题存在。 (顺便说一句,我不得不说一件有趣的事情:自从我更新到雪豹和 xcode 3.2 后,应用程序就没有出现过这个错误......没有改变一行,这个错误就出来了)
      • 这不太可能,但您隐约发现了 api 中的错误。根据我的经验,10 次中有 9 次我认为我有一个 api 错误,但这仍然是我的错。
      • 我遇到了 m 问题,但我决定继续在我的软件中实现一些新的东西,然后再尝试解决这个问题。我几乎什么都没改变(如果按下按钮后很简单),神奇地我们讨论的错误消失了....我的假设是,升级到 Snow Leopard 和新的 Xcode 3.2 并更改为 llvm/clang链接库中断了。然后(即使我做了几次全部清理)在我修改了一些代码后重新构建项目时,一些东西就位,所以编译器必须重新链接库。
      【解决方案7】:

      虽然可能不是导致崩溃的原因,但由于没有使用 CFRelease()CFImageRelease() 等释放 context2unmaskedmask Core Foundation 对象,您正在泄漏内存。

      【讨论】:

      • 添加了 CGContextRelease() 和 CGI​​mageRelease() ,谢谢你的建议;)
      猜你喜欢
      • 2016-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2018-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多