我有一个应用程序,需要截取屏幕并将其保存为文件。我正在使用ARC,所以不要手动释放变量,而且我的代码似乎有一些严重的泄漏。
以下是我正在运行的内容:
- (BOOL) saveNow:(NSString *)filePath {
UIImage *image = [self.view getImage];
NSData *imageData = UIImagePNGRepresentation(image);
return [imageData writeToFile:filePath atomically:YES];
}
其中getImage
是UIView
上的类别方法:
- (UIImage *)getImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [[UIScreen mainScreen]scale]);
[[self layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return viewImage;
}
在非视网膜iPad上运行时,UIImage
对象的创建会使内存额外增加1 MB,NSData
再添加4 MB,因为我多次运行,这个记忆没有发布!在视网膜iPad上,每次调用saveNow:
的成本约为17 MB,这会导致设备在运行几次后内存不足。
一些额外的信息。我在一个循环中运行此代码,循环总共超过300次(每次迭代对视图进行小的更改,我需要每个的截图以供审阅)。如果我减少迭代次数以使设备不会耗尽内存,我可以看到一旦包含循环的方法返回就释放内存。但是,这并不理想,我希望将内存繁重的代码放入它自己的函数(saveNow:
)应该有所改进,但事实并非如此。如何在不需要时强制释放这些对象而不是等待父方法返回?希望无需在整个项目中禁用ARC。
编辑:我尝试使用@autoreleasepool
这样:
@autoreleasepool {
[self saveNow:filePath];
}
结果更好但不完美。当块完成时,它释放大约4 MB的内存,但是在容器方法返回之前,另外1 MB仍然停留。所以这是80%的改进(是的!)但是我的目标是100%:)我会阅读更多关于@autoreleasepool
的内容,因为我之前没有使用它。
答案 0 :(得分:3)
我会对@autoreleaspool发表评论,以帮助你解决问题。
Apple建议使用@autoreleaspool来关注内存。以下段落取自核心数据documentation,但我相信也适用于这种情况:
与许多其他情况一样,当您使用Core Data导入时 一个数据文件,重要的是要记住Cocoa的“正常规则” 应用开发适用。如果您导入了您拥有的数据文件 要以某种方式解析,很可能会创建大量的 临时对象。这些可能占用大量内存并导致 分页。就像使用非核心数据应用程序一样,您可以 使用本地自动释放池块来限制多少 其他对象驻留在内存中。有关交互的更多信息 核心数据和内存管理之间,请参阅“减少内存 开销“。
基本上,@ autoreleasepool用作编译器一旦超出范围就释放所有临时对象的提示。 您期望完全释放内存,这可能不是Apple框架的情况。窗帘后面可能会有一些缓存(这只是想法)。这就是剩下的1MB可能没问题的原因。但是,为了安全起见,我建议增加迭代次数,看看会发生什么。
正如您在评论中提到的,您的循环很大并且是嵌套的,因此可能还会有其他内容发生。尝试摆脱所有额外的操作,看看会发生什么。
希望这有帮助,干杯!