-[UIImage drawInRect:] / CGContextDrawImage()没有释放内存?

3

我想要在背景图片之上轻松地混合UIImage,因此编写了一个适用于UIImage的类别方法,该方法改编自基于顶部图像的alpha/透明度混合两个UIImage

- (UIImage *) blendedImageOn:(UIImage *) backgroundImage  {
 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 UIGraphicsBeginImageContext(backgroundImage.size);

 CGRect rect = CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height);
 [backgroundImage drawInRect:rect];
 [self drawInRect:rect];
 UIImage* blendedImage = [UIGraphicsGetImageFromCurrentImageContext() retain];

 UIGraphicsEndImageContext();
 [pool release];

 return [blendedImage autorelease];
}

很不幸,我使用以上方法加载大约20张图片,并将它们与背景和光泽图像混合(因此可能涉及40个调用)的应用在设备上被强制退出。仪器会话揭示,由于调用drawInRect:而导致的malloc调用占用了大部分内存。我尝试用等效的函数调用CGContextDrawImage替换了drawInRect:消息,但没有帮助。我们在发现内存使用问题后添加了AutoReleasePool,但也没有产生任何影响。
我认为这可能是因为我没有正确使用图形上下文。在循环中调用上述方法是否是一个坏主意,因为我创建了许多上下文?还是我简单地错过了什么?
- 编辑1:感谢评论。该方法在控制器方法中被调用,该方法设置了20个视图,因此在循环中我有以下调用:
    UIImage *blendedImage = [newImage blendedImageOn:backgroundImage];

我添加了自动释放池以确保在主自动释放池释放它们之前释放图像,理论上当循环结束时所有新的UIImages对象都应该被释放。但是,分析结果显示,无论是否存在自动释放池,都没有任何区别。
- 编辑2:是的,我也尝试在调用blendedImageOn:之前添加自动释放池,但没有效果。
- 编辑3:修复了由于自动释放池而释放UIImage的令人尴尬的错误。自动释放池的目的是释放除结果UIImage之外的任何对象,以防过多的内存是由于添加到主自动释放池中的临时对象导致的,这些对象不会立即被释放。
我试图询问的问题(我承认表述得非常糟糕!)是:为什么调用此方法20次会导致大量内存使用?
4个回答

1

不应直接调用drawRect:方法。请使用[self setNeddsDisplay];代替(这不会帮助您解决泄漏问题);

关于您的泄漏问题,请删除与池有关的所有内容。 您的方法返回自动释放的UIImage对象。 请粘贴您使用返回的UIImage的代码,我将能够帮助您。 很可能您应该在调用blendedImageOn:的地方创建池,并在每3-5次迭代中清空池。


1
它是drawInRect,用于将一张图片写入另一张图片。非常确定setNeedsDisplay不会做到这一点! - walkytalky
抱歉,我的错误,应该读取drawRect:而不是drawInRect。 无论如何,答案的第二部分仍然有效。最好展示作者如何调用blendedImageOn方法。 - OgreSwamp
捕获池中的自动释放对象,加1。 (听起来全都不对。) - walkytalky

1

我找到了过度内存使用的问题所在。我的图像比我预期的要大得多,将背景图像调整为视图大小,然后调用发布方法将其绘制到图形上下文中,解决了内存使用问题。

我仍然困惑为什么当图像上下文结束时内存没有被回收。


0

你的代码存在一个问题,就是你获取的blendedImage对象被标记为自动释放,当你释放临时自动释放池时,blendedImage也会被释放。

你可以在池被释放之前保留它,然后返回自动释放的对象:

...
UIImage* blendedImage = UIGraphicsGetImageFromCurrentImageContext(); 

UIGraphicsEndImageContext();
[blendedImage retain];       // keep this past pool release
[pool release];

[blendedimage autorelease];  // now it will be autoreleased from the main pool

return [blendedImage release];  // release to balance out the retain above

程序员,好眼力。实际上,我发布了一个不表现出我的症状但展示了完全不同的内存问题的疑难代码。对此,我很抱歉:-( 我已经编辑了代码并重新描述了问题,希望能够澄清我遇到的问题。 - sohocoke

0
根据iPhone内存使用指南,任何返回“拥有”对象(非自动释放)的方法都应该以“alloc”或“new”开头,或者包含“copy”。
你的名字“blendedImageOn”没有遵循这些准则。如果你在一个月内使用它,或者其他人使用它,你不会记得图像被保留在内部,你将会有一个内存泄漏。

关于名称的观点很好,我想名称应该更加详细,改为'imageByBlendingImage:'。然而,该方法并没有返回一个'owned'对象,因为由于自动释放池,保留计数应该平衡为0。这符合内存使用准则:通过发送release消息或autorelease消息(autorelease在“Autorelease”中有更详细的讨论),您可以放弃对对象的所有权。在Cocoa术语中,放弃对对象的所有权通常被称为“释放”对象。 - sohocoke
抱歉...看起来我可能是在注释旧版本的代码,或者我没有看清楚;-) 当然现在代码返回一个自动释放的对象,方法名也正确。 - Adam Woś

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接