如何在不崩溃的情况下解决CoreGraphics Memory Leak问题?

时间:2012-05-16 15:36:57

标签: user-interface core-graphics automatic-ref-counting cgimage

我有一个代码迭代器,它是一个测试函数,用于将原始数据转换为UIImage对象以进行文件存储。我有两个失败路径或选项。我可以失败:

A.)通过泄漏(仪器没有显示它 - 仪器所有分配似乎都是稳定的,我必须多次迭代50次,它会通过仪器或正常情况运行测试功能) 。由于下面的“b”选项,记忆似乎是罪魁祸首。

B.)我可以在UIImage中强制释放CG对象,在这种情况下应用程序将继续。一旦迭代器完成,测试将在最后一次迭代时崩溃,试图释放从我的子函数返回的图像下面的CGImage。无论我请求多少次迭代,迭代器都会完成它的运行。这将指出我已修复泄漏的事实。那么现在我想把最后一次迭代的特殊内容拼凑起来? (ARC?)

- (UIImage *) convertRGBToUIImage:(unsigned char *) buffer 
                            withWidth:(int) width
                           withHeight:(int) height 
{

   CGColorSpaceRef colorSpace       = nil;
   CGContextRef    context          = nil;
   CGImageRef      ref              = nil;
   UIImage        *retImg           = nil;

   colorSpace = CGColorSpaceCreateDeviceRGB();
   if (colorSpace == NULL)
   {
      NSLog(@"ERROR: allocating color space convert Bitmap\n");
      return nil;
   }

   context = CGBitmapContextCreate (buffer, width, height, 8, width * 4, colorSpace,     kCGImageAlphaPremultipliedLast);
   CGColorSpaceRelease(colorSpace );

   if (context == NULL)
   {
     NSLog(@"ERROR: Context not created!");
     return nil;
   }

   ref = CGBitmapContextCreateImage(context);                                     
   CGContextRelease(context);

   retImg = [UIImage imageWithCGImage:ref];
   CGImageRelease(ref);

   return retImg;
}

迭代器基础知识

for(int i = 0; i < numberiterations; i++)
{ 
    UIImage *completedImage = [phelper convertRGBToUIImage:pBuffer withWidth:width withHeight:height]

    //...save it out or display it

    //Turn on one of the scenarios below

    //scenario "A" -- will leak memory (instruments doesn't seem to turn anything up)
    //ARC free
    //completedImage = nil; //this will leak and fail after ~50 iterations

    //-or-

    //scenario "B" -- will crash on the very last iteration every time but can run x times
    //CGImageRelease([completedImage CGImage];


}

Xcode中的分析工具更喜欢上面的场景“A”。我可以做到这一点,一切看起来都很棒,但它不会成功完成测试。我认为这指向ARC。我试图找出__bridge类型的转换没有成功。我似乎无法正确使用语法,也许它不是我的问题的答案。任何提示或想法都将非常感激。

1 个答案:

答案 0 :(得分:3)

仪器没有出现泄漏的原因是 - 技术上 - 没有

你所看到的是来自@autoreleasepool的记忆压力不够紧张:

您的方法convertRGBToUIImage:withWidth:withHeight:会返回一个新的自动释放图像,但最接近的@autoreleasepool位于您的循环之外。

这意味着在你的循环所在的方法返回之前,所有这些图像都不会被处理掉。

这就是为什么你看到你的内存消耗在方案A中每次迭代都在增长而你的应用程序在方案B中的循环之后崩溃的原因:

UIImage - 主要是 - 围绕CGImageRef的Objective-C包装器,以便方案B中的额外CGImageReleaseUIImage下方拉出后备存储脚。这个后备存储恰好是UIImage内存饥渴的部分,所以内存消耗的急剧增加几乎消失了。

在返回循环的方法后,当@autoreleasepool 耗尽时,它会处理所有临时UIImage个实例 - 而这些实例又要处置它们的后备 - CGImageRef ...和热潮会有节目。

诀窍是在循环中创建自己的@autoreleasepool

for (int i = 0; i < numberiterations; i++) {
    @autoreleasepool {
        // your old iteration body comes here
    }
}

现在,方案A将按预期运行,方案B将在第一次迭代结束时立即崩溃 - 这也是预期的。


现在对于一些严重的大脑f ** k:

如果您在“发布”方案下在ARC下运行原始代码,(即编译器标志-Os又称“最快的最小”),方案A很可能不会崩溃!

这种看似奇怪的行为的原因是,ARC使用一组执行实际内存管理的特殊C函数来装饰您的代码 - 并且因为这些函数是常量的(Objective-C中的方法调用不一定)编译器可以优化它们的某些组合。

这导致UIImage永远不会被插入自动释放池中,因此在循环的每次迭代后被处理掉。

相关问题