我有一个需要截图并保存为文件的应用程序。我使用的是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
的内容,因为我以前从未使用过它。 最佳答案
我会在@autoreleaspool上发表自己的评论,这是对您有帮助的合法答案。
苹果建议在内存有问题的地方使用@autoreleaspool。以下段落摘自Core Data documentation,但我相信也可以在这种情况下应用:
与许多其他情况一样,当您使用Core Data进行导入时
数据文件,记住可可的“正常规则”很重要
应用开发适用。如果您导入的数据文件
以某种方式进行解析,您可能会创建大量的
临时对象。这些可能会占用大量内存并导致
分页。就像使用非核心数据应用程序一样,您可以
使用本地自动释放池块来限制数量
其他对象驻留在内存中。有关交互的更多信息
在核心数据和内存管理之间,请参阅“减少内存
高架。”
基本上,@ autoreleasepool可以作为编译器在所有临时对象超出范围后释放它们的提示。
您期望内存可以完全释放,Apple框架可能不会这样。幕后可能会有一些缓存(这是公正的想法)。这就是为什么剩余的1MB可能还可以的原因。但是,为了安全起见,我建议增加迭代次数,然后看看会发生什么。
正如您在评论中提到的那样,您的循环很大且嵌套,因此可能还会发生其他情况。尝试摆脱所有额外的操作,看看会发生什么。
希望这会有所帮助,干杯!
关于ios - UIImage和NSData内存泄漏,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21099661/