UIGraphicsGetImageFromCurrentImageContext 内存泄漏与预览
Posted
技术标签:
【中文标题】UIGraphicsGetImageFromCurrentImageContext 内存泄漏与预览【英文标题】:UIGraphicsGetImageFromCurrentImageContext memory leak with previews 【发布时间】:2011-07-04 12:22:00 【问题描述】:我正在尝试在 PDF 中创建页面的预览图像 但是我在释放内存时遇到了一些问题。
我写了一个简单的测试算法来循环这个问题, 应用在第 40 次迭代附近崩溃:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:@"myPdf.pdf"];
CFURLRef url = CFURLCreateWithFileSystemPath( NULL, (CFStringRef)pdfPath, kCFURLPOSIXPathStyle, NO );
CGPDFDocumentRef myPdf = CGPDFDocumentCreateWithURL( url );
CFRelease (url);
CGPDFPageRef page = CGPDFDocumentGetPage( myPdf, 1 );
int i=0;
while(i < 1000)
UIGraphicsBeginImageContext(CGSizeMake(768,1024));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,CGRectMake(0, 0, 768, 1024));
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, 1024);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
// --------------------------
// The problem is here (without this line the application doesn't crash)
UIImageView *backgroundImageView1 = [[UIImageView alloc] initWithImage:UIGraphicsGetImageFromCurrentImageContext()];
// --------------------------
UIGraphicsEndImageContext();
[backgroundImageView1 release];
NSLog(@"Loop: %d", i++);
CGPDFDocumentRelease(myPdf);
上述行似乎产生了内存泄漏, 但是,instruments 没有显示内存问题;
我可以摆脱这种错误吗?有人可以用哪种方式解释我吗? 还有其他方法可以显示 pdf 的预览吗?
更新
我认为问题不在于UIGraphicsGetImageFromCurrentImageContext()
方法创建的UIImage
的发布,而是使用此自动释放图像创建的UIImageView
的发布。
我把这行代码分成了三个步骤:
UIImage *myImage = UIGraphicsGetImageFromCurrentImageContext();
UIImageView *myImageView = [[UIImageView alloc] init];
[myImageView setImage: myImage]; // Memory Leak
第一行和第二行不会造成内存泄漏,所以我认为 UIGraphicsGetImageFromCurrentImageContext 方法不是问题。
我也尝试了以下方法,但问题仍然存在:
UIImageView *myImageView = [[UIImageView alloc] initWithImage:myImage];
我认为发布包含具有 autorelease 属性的 UIImage 的 UIImageView 存在内存泄漏。
如thread 中所述,我尝试编写继承 UIView 的对象 UIImageView。
此解决方案有效但不是很优雅,这是一种解决方法,我更喜欢使用对象 UIImageView 解决内存问题。
【问题讨论】:
您使用什么工具来检查内存使用情况?我会查看“分配”和“活动监视器”,它们都可以显示泄漏工具遗漏的内存使用情况。另外,这段代码到底应该做什么?您想创建 1000 个图像视图,然后在不使用它们的情况下摆脱它们? 你找到答案了吗?我有同样的问题:S 【参考方案1】:问题是这样的:
UIGraphicsGetImageFromCurrentImageContext()
返回一个自动释放的UIImage
。自动释放池会保留此映像,直到您的代码将控制权返回给运行循环,而您很长一段时间都不会这样做。要解决此问题,您必须在 while
循环的每次迭代(或每隔几次迭代)上创建并排出一个新的自动释放池。
【讨论】:
我尝试在每次迭代时创建和释放 NSAutoreleasePool,但内存问题仍然存在。无论如何感谢您的回复! 为我工作。感谢您的提示! 编码人员(包括我自己)常犯的一个错误是将自动释放池放在循环之外,而不是在循环内部。非常感谢您澄清这一点! ***.com/questions/46903182/…【参考方案2】:我知道这是一个老问题,但我已经为此苦苦思索了几个小时。在我的应用中反复调用
UIImage *image = UIGraphicsGetImageFromCurrentImageContext()
尽管我调用 image = nil; 在一个循环中确实保留了内存;不确定应用程序在释放之前会保留内存多长时间,但它肯定足以让我的应用程序收到内存警告然后崩溃。
我最终通过将调用/使用来自 UIGraphicsGetImageFromCurrentImageContext() 的图像的代码包装在 @autoreleasepool 中来解决它。所以我有:
@autoreleasepool
UIImage *image = [self imageWithView:_outputImageView]; //create the image
[movie addImage:image frameNum:i fps:kFramesPerSec]; //use the image as a frame in movie
image = nil;
希望对某人有所帮助。
【讨论】:
【参考方案3】:为了将来参考,这是我为解决这个问题所做的(在 Swift 4 中测试)。
我为从 Internet 下载的每个新图像(在实用程序队列上)调用下面的函数。在实现自动释放池之前,它会在处理大约 100 个后崩溃。
为简单起见,在 resizeImage 函数中,我删除了除自动释放池和泄漏部分之外的所需代码。
private func resizeImage(image: UIImage, toHeight: CGFloat) -> UIImage
return autoreleasepool () -> UIImage in
[...]
let newImage = UIGraphicsGetImageFromCurrentImageContext() //Leaked
UIGraphicsEndImageContext()
return newImage!
我希望这会有所帮助!
【讨论】:
这与现有答案有何不同?您正在使用自动释放池。至少有两个现有答案说要这样做。 以前的答案没有显示与 Swift 4 兼容的自动释放池实现返回值。至少我无法仅通过查看此页面来找出解决方案,这就是为什么我希望我的回答能帮助其他处于类似情况的人。 好的,但现在循环在哪里?问题是关于在循环中获取图像。如果没有循环,则不需要 自动释放池。我只是想看看我们是否可以让您的回答更有用/更准确。 刚刚编辑了答案以帮助澄清。感谢您的反馈马特。 非常好!这解释得很好。【参考方案4】:对于那些尝试了上述所有解决方案但仍然存在内存泄漏的人,请检查您是否使用了调度队列。如果是这样,请务必将其 autoreleaseFrequency 设置为 .workItem。或者你在里面设置的自动释放池不会执行。
DispatchQueue(label: "imageQueue", qos: .userInitiated, autoreleaseFrequency: .workItem)
希望它有所帮助,它困扰了我好几个小时,直到我终于意识到是 DispatchQueue 持有该块。
【讨论】:
【参考方案5】:这段代码是否在主线程上运行? UIGraphicsGetImageFromCurrentImageContext (link) 的文档说它必须以这种方式运行。
【讨论】:
是的,我阅读了 Apple 文档。我在主线程上调用这个函数,谢谢你的回复! 来自UIGraphicsGetImageFromCurrentImageContext
上的最新 UIKit 文档:In ios 4 and later, you may call this function from any thread of your app.
【参考方案6】:
你的崩溃行你可以像下面这样更新它
让一个 UIimage 退出循环
rendered_image = UIGraphicsGetImageFromCurrentImageContext();
【讨论】:
以上是关于UIGraphicsGetImageFromCurrentImageContext 内存泄漏与预览的主要内容,如果未能解决你的问题,请参考以下文章