UIGraphicsGetImageFromCurrentImageContext内存泄漏预览

Ale*_*dro 16 memory objective-c uikit cgcontext ios

我正在尝试在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);
Run Code Online (Sandbox Code Playgroud)

上述线路似乎会产生内存泄漏,但是,仪器不会出现内存问题;

我可以摆脱这种错误吗?有人可以用哪种方式解释我?是否有其他方式来显示pdf的预览?

UPDATE

我认为问题不是该UIImage方法创建UIGraphicsGetImageFromCurrentImageContext()的版本,而是UIImageView使用此自动释放图像创建的版本.

我将代码行分为三个步骤:

UIImage *myImage = UIGraphicsGetImageFromCurrentImageContext();
UIImageView *myImageView = [[UIImageView alloc] init];
[myImageView setImage: myImage]; // Memory Leak
Run Code Online (Sandbox Code Playgroud)

第一行和第二行不会造成内存泄漏,所以我认为方法UIGraphicsGetImageFromCurrentImageContext不是问题.

我也尝试如下但问题仍然存在:

UIImageView *myImageView = [[UIImageView alloc] initWithImage:myImage];
Run Code Online (Sandbox Code Playgroud)

我认为UIImageView的发布中存在内存泄漏,其中包含具有autorelease属性的UIImage.

我尝试编写我的对象UIImageView继承UIView,如此线程中所述.

这个解决方案有效,但不是很优雅,这是一个解决方法,我宁愿使用对象UIImageView解决内存问题.

Ole*_*ann 26

问题是这样的:

UIGraphicsGetImageFromCurrentImageContext()
Run Code Online (Sandbox Code Playgroud)

返回自动释放UIImage.自动释放池保留此图像,直到您的代码将控制权返回到runloop,这是您很长时间没有做到的.要解决此问题,您必须在循环的每次迭代(或每几次迭代)中创建并排空新的自动释放池while.

  • 我尝试在每次迭代时创建并释放NSAutoreleasePool,但内存问题仍然存在.无论如何,谢谢您的回复! (2认同)

Cha*_*esA 14

我知道这是一个古老的问题,但我刚刚将头撞在墙上几个小时.在我的应用程序反复调用

UIImage *image = UIGraphicsGetImageFromCurrentImageContext()
Run Code Online (Sandbox Code Playgroud)

尽管我调用了image = nil,但是在循环中确实保留了内存; 不知道应用程序在释放之前会持续多长时间来保持内存,但它确实足够长,以便我的应用程序获得内存警告然后崩溃.

我设法通过包装调用/使用@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;
}
Run Code Online (Sandbox Code Playgroud)

希望可能对某人有所帮助.


MMV*_*MMV 5

为了将来参考,这是我为解决此问题所做的工作(在 Swift 4 中测试)。

我正在为从互联网下载的每个新图像(在实用程序队列中)调用下面的函数。在实现自动释放池之前,它会在处理大约 100 个之后崩溃。

为简单起见,在 resizeImage 函数中,除了 autoreleasepool 和泄漏的部分之外,我删除了所需的代码。

private func resizeImage(image: UIImage, toHeight: CGFloat) -> UIImage {
    return autoreleasepool { () -> UIImage in
        [...]

        let newImage = UIGraphicsGetImageFromCurrentImageContext() //Leaked
        UIGraphicsEndImageContext()

        return newImage!
    }

}
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助!


Ric*_*llo 1

这段代码是在主线程上运行的吗?UIGraphicsGetImageFromCurrentImageContext(链接)的文档表明它必须以这种方式运行。

  • 来自最新的 UIKit 文档“UIGraphicsGetImageFromCurrentImageContext”:“在 iOS 4 及更高版本中,您可以从应用程序的任何线程调用此函数。” (9认同)