【问题标题】:UIImage and NSData memory leakUIImage 和 NSData 内存泄漏
【发布时间】:2014-01-13 19:26:28
【问题描述】:

我有一个需要截取屏幕截图并将其保存为文件的应用程序。我使用的是 ARC,所以没有手动释放变量,而且我的代码似乎有一些严重的泄漏。

这是我正在运行的:

- (BOOL) saveNow:(NSString *)filePath {
    UIImage *image = [self.view getImage];
    NSData *imageData = UIImagePNGRepresentation(image);
    return [imageData writeToFile:filePath atomically:YES];
}

其中getImageUIView 上某个类别的方法:

- (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 的信息,因为我以前没有使用过它。

【问题讨论】:

  • 尝试将你的 saveNow: 方法封装在 @autoreleasepool 中?
  • 你是在主线程还是后台线程中运行saveNow
  • 你能发布你的循环代码吗?
  • 我在主线程上运行它。循环非常大而且嵌套,我将看看发布它的简洁版本是否有意义。

标签: ios objective-c memory-leaks uiimage nsdata


【解决方案1】:

我会将我对 @autorelaspool 的评论作为一个合法的答案来帮助你。

Apple 建议在关注内存的情况下使用 @autorelaspool。以下段落摘自Core Data documentation,但我相信也可以应用于这种情况:

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

基本上,@autoreleasepool 用作提示编译器在所有临时对象超出范围时释放它们。 您期望完全释放内存,而 Apple 框架可能并非如此。窗帘后面可能会有一些缓存(这只是想法)。这就是为什么剩余的 1MB 可能没问题的原因。但是,为了安全起见,我建议增加迭代次数,看看会发生什么。

正如您在评论中提到的,您的循环很大且嵌套,因此可能会发生其他事情。尝试摆脱所有额外的操作,看看会发生什么。

希望这会有所帮助,干杯!

【讨论】:

  • 在我添加 @autoreleaspool 后,循环的其余部分中有几件事变得几乎不明显,但它们的重要性不足以引起我使用它的规模的关注.我一直在运行代码并在块之前、块末尾、块完成之后以及下一次迭代的块之前比较内存使用情况,以了解代码的哪些部分最重要影响,我想再稍微调整一下我会很满意的。谢谢!
  • 另外,使用 Time Profiler 工具可能会有一些运气。当我需要优化我的代码时,我经常使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 2013-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多