首页 文章

NSImage drawInRect和NSView cacheDisplayInRect内存保留

提问于
浏览
4

我正在处理的应用程序处理图像 . 这就像用户下降最多4张图片和应用程序根据用户选择的模板布局它们 . 最终视图中可能会添加2-3张图像 .

布局中的每个图像都是在NSView(使用drawInRect方法的NSView的drawRect方法)中绘制的 . 现在,通过将NSView保存为图像来创建最终图像(通过布局所有图像组合图像),并且它们都能很好地工作 .

现在我遇到的问题是,所有处理完成后,应用程序将保留内存 . 我已经使用了仪器分配,我没有看到内存泄漏,但我看到“持久字节”在应用程序的每个会话和GB的一个用户报告的问题中不断增加 . 请看截图 .

Instruments memory usage

ImageIO_TIFF
当我在Instruments中进一步调查时,我看到了导致内存保留的应用程序的代码捕捉 . 所有这些都与ImageIO和coreImages有关 . 从仪器见下文:

Instruments code snap

然而,这似乎只是10.10及以上系统的问题 . 在10.9.x中测试了相同版本的应用程序,内存使用率保持在60MB . 在应用程序中执行会话期间,它会达到200MB,但一旦完成它就会恢复到通常用于应用程序类型的50-60MB .

[_photoImage drawInRect: self.bounds fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0 respectFlipped: YES hints: nil];
            _photoImage = nil;

上面的代码我用来在NSView的drawRect方法中绘制图像,图像中显示的代码用于将NSView作为Image .

Update: 在我进一步调查后,我发现它是 CGImageSourceCreateWithData 缓存了NSImage的TIFF数据 . 更多的是我使用下面的代码来裁剪图像,如果我取消注释它的内存消耗只是工作正常 .

NSData *imgData = [imageToCrop TIFFRepresentation];
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imgData, NULL);
CGImageRef maskRef =  CGImageSourceCreateImageAtIndex(source, 0, NULL);
CGImageRef imageRef = CGImageCreateWithImageInRect(maskRef, rect);
NSImage *cropped = [[NSImage alloc] initWithCGImage: imageRef size:rect.size];

CGImageRelease(maskRef);
CGImageRelease(imageRef);
CFRelease(source);
//CFRelease( options );
imgData = nil;

我也尝试明确设置 kCGImageSourceShouldCache to false (但它默认为false)但结果相同 . 请帮助解决内存保留问题 .

1 回答

  • 1

    最后经过大量调试后发现 CGImageSourceCreateWithData 在某处保留了NSImage的TIFF数据 . 当我更改此行时:

    CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imgData, NULL);
    

    CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path], NULL);
    

    一切都刚刚开始正常工作,应用程序的内存使用率从300MB(6images)降至50-60MB,现在它的行为一致 .

    除了上面的更改,它仍然导致内存保留在某处,所以要摆脱它,在所有处理完成后,我清除每层的图像到 'nil' ,这就像魅力 . 我的印象是,将父母视为 'nil' 也会释放图像,但这不起作用 .

    无论如何,如果有任何人似乎与drawInRect或cacheDisplayInRect有关,那么请确保在以后不需要时清除图像 .

    Update 2nd July 2016

    我发现默认情况下 kCGImageSourceShouldCache 在32位时为false,对于64位为true . 通过将其设置为false,我能够使用以下代码释放内存 .

    const void *keys[] =   { kCGImageSourceShouldCache};
        const void *values[] = { kCFBooleanFalse};
        CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    
        CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)[image TIFFRepresentation], optionsDictionary);
    

    希望它可以帮助某人 .

相关问题