保留 NSImage drawInRect 和 NSView cacheDisplayInRect 内存
NSImage drawInRect and NSView cacheDisplayInRect memory retained
我正在处理图像的应用程序。这就像用户最多放置 4 张图像并根据用户选择的模板对它们进行布局。一张图片在最终视图中可能会添加 2-3 次。
布局中的每个图像都是在 NSView 中绘制的(使用 drawInRect 方法的 NSView 的 drawRect 方法)。现在通过将 NSView 另存为 Image 创建最终图像(通过布局所有图像的组合图像)并且一切正常。
现在我面临的问题是,一旦所有处理完成,应用程序就会保留内存。我已经使用了仪器分配,但我没有看到内存泄漏,但我看到 "Persistent bytes" 随着应用程序的每个会话不断增加,并且一个用户报告了 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),但结果相同。
请帮助解决内存保留问题。
经过大量调试,最终发现 CGImageSourceCreateWithData 在某处保留了 NSImage 的 TIFF 数据。当我更改此行时:
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imgData, NULL);
和
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path], NULL);
一切都刚刚开始正常工作,应用程序的内存使用量从 300MB(对于 6 张图像)下降到 50-60MB,并且现在是一致的行为。
除了上面的变化,它仍然在某处造成内存保留,所以为了摆脱它,在完成所有处理后,我将每一层的图像清除为 'nil'这就像魅力一样。我的印象是将父级设置为 'nil' 也会发布图像,但那是行不通的。
无论如何,如果有人认为 drawInRect 或 cacheDisplayInRect 有问题,请确保在以后不需要时清除图像。
2016 年 7 月 2 日更新
我发现 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);
希望对大家有所帮助。
我正在处理图像的应用程序。这就像用户最多放置 4 张图像并根据用户选择的模板对它们进行布局。一张图片在最终视图中可能会添加 2-3 次。
布局中的每个图像都是在 NSView 中绘制的(使用 drawInRect 方法的 NSView 的 drawRect 方法)。现在通过将 NSView 另存为 Image 创建最终图像(通过布局所有图像的组合图像)并且一切正常。
现在我面临的问题是,一旦所有处理完成,应用程序就会保留内存。我已经使用了仪器分配,但我没有看到内存泄漏,但我看到 "Persistent bytes" 随着应用程序的每个会话不断增加,并且一个用户报告了 GB 的问题。请看截图。
然而这似乎只是 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),但结果相同。 请帮助解决内存保留问题。
经过大量调试,最终发现 CGImageSourceCreateWithData 在某处保留了 NSImage 的 TIFF 数据。当我更改此行时:
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)imgData, NULL);
和
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path], NULL);
一切都刚刚开始正常工作,应用程序的内存使用量从 300MB(对于 6 张图像)下降到 50-60MB,并且现在是一致的行为。
除了上面的变化,它仍然在某处造成内存保留,所以为了摆脱它,在完成所有处理后,我将每一层的图像清除为 'nil'这就像魅力一样。我的印象是将父级设置为 'nil' 也会发布图像,但那是行不通的。
无论如何,如果有人认为 drawInRect 或 cacheDisplayInRect 有问题,请确保在以后不需要时清除图像。
2016 年 7 月 2 日更新
我发现 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);
希望对大家有所帮助。