【问题标题】:Image IO memory keeps growing图像 IO 内存不断增长
【发布时间】:2013-08-15 15:31:45
【问题描述】:

我在 Instruments 中使用 VM Tracker 运行我的应用,发现 Image IO 内存消耗不断增加。

实际上,该应用使用initWithContentsOfFile: 从磁盘读取了很多图像。我曾经读到这个方法是撒旦的产物,所以我用下面的方法替换它:

NSData *data = [NSData dataWithContentsOfFile:path];
UIImage *image = [UIImage imageWithData:data];

这大大减少了虚拟内存(约60%),如下图:

但是,为什么 Image IO 虚拟内存会随着时间的推移而不断增长,而没有任何泄漏并且我的应用程序只使用 15MB 的实时内存?

我可以做些什么来确保这个 Image IO 内存被释放?

基本上,从磁盘读取图像是这样完成的:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^(void) {
    NSData *data = [NSData dataWithContentsOfFile:path];
    UIImage *image = [UIImage imageWithData:data];
    dispatch_async(dispatch_get_main_queue(), ^{
        imageView.image = image;
    });
});

我还尝试了以下没有任何重大变化的方法:

  • 改用[NSData dataWithContentsOfFile:path options:NSDataReadingUncached error:nil]
  • UIImage *image = [UIImage imageWithData:data]; 移至主队列
  • 在主队列上做所有事情

这让我觉得问题可能出在其他地方。

【问题讨论】:

  • 在分配工具中,您可以将调用堆栈的所有记录转换为分配事件。也许你在某处有一个额外的意外保留?
  • @nielsbot 如果有,那么实时内存会不会更高(更接近虚拟内存)?也就是说,我已经检查了 Instruments 和静态分析仪中的泄漏。
  • 我想我主要是对分配的来源感到好奇。
  • @nielsbot 给你 :) imgur.com/UowiGKR
  • 好的——看起来有很多 CFData 对象...如果单击 CFData 旁边的显示详细信息箭头然后浏览实例,查看每个分配事件的记录调用堆栈以查看分配的原因。

标签: ios uiimage instruments


【解决方案1】:

您至少应该将后台处理包装到一个自动释放池中:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^(void) {
    @autoreleasepool {
        NSData *data = [NSData dataWithContentsOfFile:path];
        UIImage *image = [UIImage imageWithData:data];
        dispatch_async(dispatch_get_main_queue(), ^{
            imageView.image = image;
        });
    }
});

这样可以确保后台线程上的所有自动释放对象尽快消失。

【讨论】:

  • ARC 不是让这变得不必要吗?知道data可以在imageWithData:之后释放,image可以在第二个dispatch_async结束时释放,这不是很聪明吗?
  • @hpique 否。如果启用优化并且调用者和被调用者都使用 ARC 编译,ARC 有时可能会避免将对象放入自动释放池中,但您不能依赖它。这里dataWithContentsOfFile: 创建了一个自动释放的对象,如果添加了池,该对象会更快地消失。
【解决方案2】:

感谢Heapshot Analysis我发现图片被NSCache保留了。

问题是NSCache 没有释放内存警告中的任何对象。解决方案:让它观察UIApplicationDidReceiveMemoryWarningNotification,并在发生这种情况时删除它的所有对象。这是 Instruments 现在的样子:

乐器很棒。感谢@NikolaiRuhe 和@nielsbot 让我深入挖掘。

另外,我应该补充一点,使用NSData 时内存消耗降低了,因为dataWithContentsOfFile不考虑视网膜文件(d'uh)。所以imageWithContentsOfFile: 可能仍然是撒旦的产物,但这不是它的错。

【讨论】:

  • 您也可以尝试将NSDataReadingMappedAlways 传递给dataWithContentsOfURL:options:error:
猜你喜欢
  • 2013-10-20
  • 2016-02-24
  • 2013-01-09
  • 2017-11-09
  • 2018-09-17
  • 1970-01-01
  • 2013-10-08
  • 2015-02-23
  • 2012-01-11
相关资源
最近更新 更多