图像IO内存不断增长

4

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

Instruments with initWithContentsOfFile:

实际上,该应用程序从磁盘读取了大量图像,使用了initWithContentsOfFile:方法。我曾经听说这个方法是“撒旦的产物”,所以我将它替换为以下方法:

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

这样做大大减少了虚拟内存(约60%),如下所示:

Instruments with imageWithData:

但是,当没有任何泄漏且我的应用程序仅使用15MB的实时内存时,为什么Image IO虚拟内存会随着时间而增长? 有什么我可以做的来确保释放这个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
@nielsbot 如果有的话,实时内存不会比虚拟内存高得多吗?话虽如此,我已经在Instruments和静态分析器中检查了泄漏。 - hpique
我猜我主要是对分配的来源感到好奇。 - nielsbot
@nielsbot 在这些对象的堆栈跟踪中找不到用户代码。 - hpique
@NikolaiRuhe 是的,我有。我已经编辑了可能引起问题的代码。你有什么想法是错在哪里了吗? - hpique
显示剩余3条评论
2个回答

2

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

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
@hpique 不是的。如果开启了优化并且调用者和被调用者都使用ARC编译,ARC有时可以避免将对象放入自动释放池中,但您不能依赖这一点。在这里,“dataWithContentsOfFile:”创建了一个自动释放的对象,如果添加了池,则该对象会更快地消失。 - Nikolai Ruhe

1
感谢Heapshot Analysis,我发现图像是由NSCache保留的。
问题在于NSCache在内存警告时不释放任何对象。解决方法:让它观察UIApplicationDidReceiveMemoryWarningNotification,并在此发生时删除其所有对象。这就是Instruments现在的样子:

Instruments with memory warning draining

乐器很棒。感谢@NikolaiRuhe和@nielsbot让我深入了解。
此外,当使用NSData时,内存消耗会降低,因为dataWithContentsOfFile没有考虑视网膜文件(傻瓜)。所以imageWithContentsOfFile:可能仍然是魔鬼的孩子,但这不是它的错。

дљ†дєЯеПѓдї•е∞ЭиѓХе∞Ж NSDataReadingMappedAlways дЉ†йАТзїЩ dataWithContentsOfURL:options:error:гАВ - nielsbot

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