我想轻松地将 UIImage 混合到另一个背景图像之上,因此为 UIImage 编写了一个类别方法,改编自 混合两个基于顶部图像的 alpha/透明度的 uiimages :
- (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 个调用),正在设备上被抛弃。
Instruments 会话显示,源自对drawInRect: 的调用对malloc 的调用造成了大部分内存使用。我尝试用对函数 CGContextDrawImage 的等效函数调用替换 drawInRect: 消息,但没有帮助。 AutoReleasePool是我发现内存使用问题后添加的;这也没有什么区别。
我想这可能是因为我没有正确使用图形上下文。由于我创建的上下文数量较多,在循环中调用上述方法会是一个坏主意吗?或者我只是错过了什么?
-
编辑1:感谢您的评论。该方法在设置 20 个视图的控制器方法中调用,因此在循环中我进行了以下调用:
UIImage *blendedImage = [newImage blendedImageOn:backgroundImage];
我添加了自动释放池以确保在主自动释放池释放图像之前释放图像,因此理论上所有循环完成后应释放新的 UIImages 对象。无论自动释放池是否在其中,分析结果都没有显示任何差异。
-
编辑2:是的,我也尝试在调用 blendedImageOn: 之前添加自动释放池,但没有效果。
-
编辑3:修复了由于自动释放池而导致UIImage被释放的尴尬错误。自动释放池的目的是释放除结果 UIImage 之外的任何对象,以防由于添加到主自动释放池中的临时对象未立即释放而导致内存过多。
我想问的问题(非常糟糕,我承认!)是:为什么调用这个方法 20 次会导致大量内存使用?
I wanted to easily blend a UIImage on top of another background image, so wrote a category method for UIImage, adapted from blend two uiimages based on alpha/transparency of top image :
- (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];
}
Unfortunately my app that uses the above method to load around 20 images and blend them with background and gloss images (so probably around 40 calls), is being jettisoned on the device.
An Instruments session revealed that calls to malloc stemming from the calls to drawInRect: are responsible for the bulk of the memory usage. I tried replacing the drawInRect: messages with equivalent function calls to the function CGContextDrawImage but it didn't help. The AutoReleasePool was added after I found the memory usage problem; it also didn't make a difference.
I'm thinking this is probably because I'm not using graphics contexts appropriately. Would calling the above method in a loop be a bad idea because of the number of contexts I create? Or did I simply miss something?
-
Edit 1: thanks for the comments. The method is invoked in a controller method that sets up 20 views, so in a loop I have the following call:
UIImage *blendedImage = [newImage blendedImageOn:backgroundImage];
I added the autorelease pool to make sure the images are released before the main autorelease pool will release them, so theoretically all of the new UIImages objects should be released when the loop has finished. The profiling results don't show any difference whether the autorelease pool is in there or not.
-
Edit 2: And yes, I've tried adding an autorelease pool before the call to blendedImageOn: as well, to no effect.
-
Edit 3: fixed embarrassing bug of UIImage being released because of the autorelease pool. The intention of the autorelease pool is to release any objects other than the result UIImage, in case the excessive memory is due to temporary objects added to the main autorelease pool which are not freed immediately.
The question I was trying to ask (very badly, I admit!) is: why does calling this method 20 times result in a lot of memory usage?
发布评论
评论(4)
您不应该直接调用
drawRect:
方法。使用[self setNeddsDisplay];
(它不会帮助你解决这个泄漏问题);关于你的泄漏。删除有关池的所有内容。
您的方法返回自动释放的
UIImage
对象。请将代码粘贴到您使用返回的
UIImage
的位置,我将能够为您提供帮助。您很可能应该在调用 BlendedImageOn: 的地方创建池,并每 3-5 次迭代耗尽池。
You shouldn't call
drawRect:
method directly. use[self setNeddsDisplay];
instead (it won't help you with this leak);About your leak. remove everything about pool.
Your method returns autoreleased
UIImage
object.Please paste code where you're using returned
UIImage
and I'll be able to help you.Very likely that you should make pool in place where you invoke
blendedImageOn:
and drain the pool each 3-5 iterations.我发现了内存使用过多的问题。我的图像比我预期的要大得多,在调用将它们绘制到图形上下文中的发布方法之前,将背景图像的大小调整为视图大小,解决了内存使用问题。
我仍然很困惑为什么当图像上下文结束时内存没有被回收。
I found the problem for the excessive memory usage. My images were much bigger than I'd anticipated, and resizing the background image to the view size before invoking the posted method that draws them into the graphics context, solved the memory usage.
I'm still puzzled why the memory isn't reclaimed when the image context is ended.
您的代码存在一个问题,即您获得的 blendedImage 对象被标记为自动释放,当您释放临时自动释放池时,噗,您也释放了 BlendedImage。
您可以保留直到池被释放,然后将其返回自动释放:
One problem with your code is that the blendedImage object you get is marked for autorelease and when you release the temporary autorelease pool, poof, you release blendedImage too.
You could retain until until the pool is released, then return it autoreleased:
根据iPhone内存使用指南,任何返回“拥有”对象(不是自动释放)的方法都应该以“alloc”或“new”开头,或者应该包含“copy”。
您的名字“blishedImageOn”不符合这些准则。如果你在一个月内使用它,或者其他人使用它,你将不记得图像被保留在里面,并且你会发生内存泄漏。
According to the iPhone memory usage guidelines, any method that returns an "owned" object (not autoreleased) should start with "alloc" or "new", or it should contain "copy".
Your name "blendedImageOn" doesn't follow these guidelines. If you use it in a month, or someone else uses it, you won't remember that the image is retained inside and you'll have a memory leak.