UIImage和NSData的内存泄漏问题

3

我有一个需要截屏并保存为文件的应用程序。因为我使用了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;
}

在非retina版本的iPad上运行此代码时,每次创建UIImage对象会额外占用1MB内存,NSData会再占用4MB内存,而且由于此代码需要多次运行,这些内存并不会被释放。在retina版本的iPad上,每次调用saveNow:方法大约需要消耗17MB的内存,容易导致设备在几次运行后内存耗尽。
额外说明:我在一个循环中运行该代码,总共迭代了300多次(每次迭代都对视图进行微小更改,需要对每个视图截屏以供审核)。如果我减少迭代次数以避免设备内存耗尽,那么当包含循环的方法返回后,我可以看到内存已被释放。但是,这不是理想的解决方案,我希望将内存密集型的代码移到自己的函数saveNow:中应该能够改善内存使用情况,但实际效果不佳。有没有办法在这些对象不再需要时立即释放它们,而不是等待父方法返回?最好不要禁用整个项目的ARC功能。
编辑:我尝试使用autoreleasepool,如下所示:
@autoreleasepool {
    [self saveNow:filePath];
}

结果比以前好了,但并不完美。当块完成时,它会释放约4 MB的内存,但另外1 MB仍然会被卡住,直到容器方法返回。所以,这是一个80%的改进(耶!),但我目标是100% :) 我会多读一些关于@autoreleasepool的信息,因为我以前没有使用过。


4
你可以尝试在 saveNow 方法中使用 @autoreleasepool 来优化内存管理。 - Arthur Shinkevich
你是在主线程还是后台线程上运行 saveNow - Putz1103
你能发一下你的循环代码吗? - Putz1103
我在主线程上运行这个程序。循环嵌套非常复杂,我要看一下是否有必要发布一个简洁版的代码来解决它。 - SaltyNuts
1个回答

3

我会把我的评论@autoreleaspool作为一份合法的答案来帮助你。

苹果建议在内存受到关注时使用@autoreleaspool。以下段落摘自Core Data documentation,但我认为它也适用于这种情况:

与许多其他情况类似,当您使用Core Data导入数据文件时,重要的是记住Cocoa应用程序开发的“正常规则”适用。如果您导入必须以某种方式解析的数据文件,则可能会创建大量临时对象。这些对象可能占用大量内存并导致分页。就像非Core Data应用程序一样,您可以使用本地autorelease池块来限制在内存中驻留的附加对象数量。有关Core Data和内存管理之间的交互更多信息,请参见“减少内存开销”。

基本上,@autoreleasepool 作为编译器释放所有临时对象的提示。您期望内存完全释放,但在Apple框架中可能不是这种情况。幕后可能会有一些缓存(这只是一个想法)。这就是为什么剩余的1MB可能是可以接受的原因。然而,为了安全起见,我建议增加迭代次数并查看发生了什么。
正如您在评论中提到的,您的循环很大且嵌套,所以可能还有其他问题。尝试摆脱所有多余的操作并查看发生了什么。
希望能对您有所帮助,干杯!

在添加了@autoreleaspool之后,循环的其余部分中有一些东西变得几乎不可见,但它们对我使用的规模来说不足为虑。我一直在运行代码并比较块之前、块结束时、完成后以及下一次迭代之前的内存使用情况,以了解哪些代码部分具有最显着的影响,我认为再稍微调整一下就会满意了。谢谢! - SaltyNuts
此外,您可能会在使用时间分析器工具时有所收获。当我需要优化我的代码时,我经常使用它。 - Arthur Shinkevich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接