ios UIGraphicsGetImageFromCurrentImageContext 内存泄漏与预览
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5121120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIGraphicsGetImageFromCurrentImageContext memory leak with previews
提问by Alessandro
I'm trying to create previews images of pages in a PDF but I have some problems with the release of memory.
我正在尝试在 PDF 中创建页面的预览图像,但我在释放内存时遇到了一些问题。
I wrote a simple test algorithm that cycles on the problem, the app crashes near the 40th iteration:
我写了一个简单的测试算法来循环解决这个问题, 应用程序在第 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);
The above-mentioned line seems to generate a memory leak, however, instrumentsdoesn't show memory problems;
上面提到的行似乎产生了内存泄漏,但是,仪器没有显示内存问题;
Can I escape from this kind of mistake?someone can explain me in which way? Are there other ways to show previews of a pdf?
我能摆脱这种错误吗?有人可以用什么方式解释我吗?还有其他方法可以显示 pdf 的预览吗?
UPDATE
更新
I think the problem isn't the release of UIImage
created by the method UIGraphicsGetImageFromCurrentImageContext()
but the release of UIImageView
created with this autorelease image.
我认为问题不UIImage
在于该方法UIGraphicsGetImageFromCurrentImageContext()
所UIImageView
创建的释放,而是使用此自动释放图像创建的释放。
I have divided the line of code in three steps:
我将这行代码分为三个步骤:
UIImage *myImage = UIGraphicsGetImageFromCurrentImageContext();
UIImageView *myImageView = [[UIImageView alloc] init];
[myImageView setImage: myImage]; // Memory Leak
The first and second lines doesn't create memory leaks so I think that the method UIGraphicsGetImageFromCurrentImageContext is not the problem.
第一行和第二行不会造成内存泄漏,所以我认为 UIGraphicsGetImageFromCurrentImageContext 方法不是问题。
I also tried as follows but the problem persists:
我也尝试过如下但问题仍然存在:
UIImageView *myImageView = [[UIImageView alloc] initWithImage:myImage];
I think there is a memory leak in the release of a UIImageView that contains a UIImage with the autorelease property.
我认为在包含具有 autorelease 属性的 UIImage 的 UIImageView 的发布中存在内存泄漏。
I tried to write my object UIImageView inheriting a UIView as explained in this thread.
我尝试编写我的对象 UIImageView 继承 UIView ,如该线程中所述。
This solution works but isn't very elegant, it's a workaround, I would prefer to use the object UIImageView solving the memory problem.
这个解决方案有效但不是很优雅,它是一种解决方法,我更喜欢使用对象 UIImageView 解决内存问题。
回答by Ole Begemann
The problem is this:
问题是这样的:
UIGraphicsGetImageFromCurrentImageContext()
returns an autoreleased UIImage
. The autorelease pool holds on to this image until your code returns control to the runloop, which you do not do for a long time. To solve this problem, you would have to create and drain a fresh autorelease pool on every iteration (or every few iterations) of your while
loop.
返回一个 autoreleased UIImage
。自动释放池会保留此图像,直到您的代码将控制权返回给 runloop,您很长时间都不会这样做。要解决此问题,您必须在循环的每次迭代(或每几次迭代)中创建并排空一个新的自动释放池while
。
回答by CharlesA
I know it's an old question, but I've just been banging my head against the wall on this for a few hours. In my app repeatedly calling
我知道这是一个老问题,但我已经在这个问题上撞墙了几个小时。在我的应用程序中反复调用
UIImage *image = UIGraphicsGetImageFromCurrentImageContext()
in a loop does hold on to the memory despite me calling image = nil; Not sure how long the app would keep hold of the memory before freeing, but it's certainly long enough for my app to get a memory warning then crash.
尽管我调用 image = nil,但在循环中确实保留了内存;不确定应用程序在释放之前会保留内存多长时间,但它肯定足以让我的应用程序收到内存警告然后崩溃。
I managed to solve it finally by wrapping the code that calls / uses the image from UIGraphicsGetImageFromCurrentImageContext() in @autoreleasepool. So I have:
我最终通过在@autoreleasepool 中包装调用/使用来自 UIGraphicsGetImageFromCurrentImageContext() 的图像的代码来解决它。所以我有:
@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;
}
Hope that might help someone.
希望这可以帮助某人。
回答by MMV
For future reference here's what I did to solve this (tested in Swift 4).
为了将来参考,这是我为解决此问题所做的工作(在 Swift 4 中测试)。
I was calling the function below for every new image downloaded from the internet (on a utility queue). Before implementing the autorelease pool it would crash after processing about 100.
我正在为从互联网下载的每个新图像(在实用程序队列中)调用下面的函数。在实现自动释放池之前,它会在处理大约 100 个之后崩溃。
For simplicity, in the resizeImage function I've removed needed code except for the autoreleasepool and the part that was leaking.
为简单起见,在 resizeImage 函数中,除了 autoreleasepool 和泄漏的部分之外,我删除了所需的代码。
private func resizeImage(image: UIImage, toHeight: CGFloat) -> UIImage {
return autoreleasepool { () -> UIImage in
[...]
let newImage = UIGraphicsGetImageFromCurrentImageContext() //Leaked
UIGraphicsEndImageContext()
return newImage!
}
}
I hope this helps!
我希望这有帮助!
回答by Legolas Wang
For those who tried all solution above and still has a memory leak, check if you are using a dispatch queue. If so, be sure to set its autoreleaseFrequency to .workItem. Or the autorelease pool you set up inside the will not execute.
对于那些尝试了上述所有解决方案但仍然存在内存泄漏的人,请检查您是否使用了调度队列。如果是这样,请务必将其 autoreleaseFrequency 设置为 .workItem。或者你在里面设置的自动释放池不会执行。
DispatchQueue(label: "imageQueue", qos: .userInitiated, autoreleaseFrequency: .workItem)
Hope it helps, it has bugged me for hours until I finally realize that's DispatchQueue that is holding the block.
希望它有帮助,它已经困扰了我几个小时,直到我终于意识到是 DispatchQueue 持有块。
回答by Ricardo de Cillo
回答by iamszabo
I've had the same problem working with big images. Adding a padding to an image or applying a filter resulted with 200MB of memory allocation without releasing it while the image was on the screen.
我在处理大图像时遇到了同样的问题。向图像添加填充或应用过滤器会导致 200MB 的内存分配,而图像在屏幕上时却没有释放它。
Found a working way to fix this problem:
找到了解决此问题的有效方法:
extension UIImage {
func release() -> UIImage? {
guard let data = UIImageJPEGRepresentation(self, 1.0) else { return nil }
return UIImage(data: data)
}
}
Also tried it with UIImagePNGRepresentation but it seems to not release the allocation neither.
也用 UIImagePNGRepresentation 尝试过,但它似乎也没有释放分配。
回答by Abdul Karim Khan
your line of crash you can update it like following
你的崩溃线你可以像下面这样更新它
get one UIimage out of loop
从循环中获取一张 UIimage
rendered_image = UIGraphicsGetImageFromCurrentImageContext();
render_image = UIGraphicsGetImageFromCurrentImageContext();