我正在处理的应用程序处理图像。这就像用户下降最多4张图片和应用程序根据用户选择的模板布局它们。最终视图中可能会添加2-3张图片。
布局中的每个图像都是在NSView(使用drawInRect方法的NSView的drawRect方法)中绘制的。现在,通过将NSView保存为图像来创建最终图像(通过布局所有图像来组合图像),这一切都很有效。
现在我遇到的问题是,所有处理完成后,应用程序都会保留内存。我已经使用了仪器分配,我没有看到内存泄漏,但我看到“持久字节”随着应用程序的每个会话和GB中的一个用户报告问题而不断增加。请看截图。
当我在Instruments中进一步调查时,我看到了导致内存保留的应用程序的代码捕捉。所有这些都与ImageIO和coreImages有关。见以下文书:
然而,这似乎只是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作为图像。
更新:经过进一步调查后,我发现 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明确设置为false (但默认为false)但结果相同。 请帮助解决内存保留问题。
答案 0 :(得分:2)
最后经过大量调试后发现 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有任何疑问,请确保在以后不需要时清除图像。
2016年7月2日更新
我发现 kCGImageSourceShouldCache 默认为32位,对于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);
希望它有所帮助。