带有@autorelease和ARC的Objective C For循环

Posted

技术标签:

【中文标题】带有@autorelease和ARC的Objective C For循环【英文标题】:Objective C For loops with @autorelease and ARC 【发布时间】:2016-07-19 12:22:29 【问题描述】:

作为允许审核员创建结果并将照片与其关联的应用程序的一部分(由于 Web 服务的限制,保存为 Base64 字符串)我必须在审核中遍历所有结果及其照片并设置它们的同步值为真。

在执行此循环时,我看到内存峰值从大约 40MB 跃升至 500MB(大约 350 张照片和 255 个结果),并且这个数字从未下降。平均而言,我们的用户在尝试使用此功能之前会创建大约 1000 个结果和 500-700 张照片。我尝试使用@autorelease 池来降低内存,但它似乎永远不会被释放。

    for (Finding * __autoreleasing f in self.audit.findings)
        @autoreleasepool 
            [f setToSync:@YES];
            NSLog(@"%@", f.idFinding);

        for (FindingPhoto * __autoreleasing p in f.photos)
            @autoreleasepool 
                [p setToSync:@YES];
                p = nil;
            

        
        f = nil;

        
    

关系和保留周期如下所示

Audit 强烈引用 Finding

Finding 对 Audit 的引用很弱,对 FindingPhoto 的引用很强烈

FindingPhoto 对 Finding 的引用很弱

在能够有效地循环这些对象并设置它们的属性而不导致如此巨大的内存峰值方面,我缺少什么。我假设这与循环时将这么多 Base64 字符串加载到内存中但从未被释放有关。

【问题讨论】:

这些对象是如何存储和加载的?它们不会被自动释放,因为它们仍然被您正在迭代的数组保留...... 存储在核心数据中并使用 NSFetchRequests 加载到 MutableArray 中。有没有更好的方法来加载这些,一次只加载和释放一个,因为如果太多,它会导致应用崩溃。 我应该提到的是,唯一执行的 FetchRequest 是 Audit 对象上的一个,其余的通过它们的关系访问,而不是显式加载。 如何将照片存储为外部文件并让核心数据实体提供对这些文件之一的引用(路径、URL...)?这样一来,加载核心数据关系的占用空间就会很小,而且您可以明确控制内存中的照片数量。 @PhillipMills 就像将核心数据中的 Base64 属性标记为“存储在外部记录文件中”一样简单,还是我必须全力以赴并实际写入文件存储或生成路径读回图像时到文件? 【参考方案1】:

因此,首先,请确保您在获取请求上设置了批量大小。选择一个相对较小的数字,但不要太小,因为这不是用于 UI 处理的。您希望将合理数量的对象批处理到内存中,以减少加载开销,同时降低内存使用量。尝试 50 或 100 看看效果如何,然后考虑稍微增加批量大小。

如果您正在加载的所有对象都是托管对象,那么在处理期间驱逐它们的正确方法是将它们变成故障。这是通过在上下文中调用refreshObject:mergeChanges: 来完成的。但是 - 丢弃任何更改,并且您的循环专门用于进行更改。

因此,您真正应该做的是批量保存您已修改的对象,然后将这些对象转回故障以从内存中删除数据。

因此,在您的循环中,保留一个计数器来记录您修改了多少,并在每次点击该计数时保存上下文并刷新到目前为止已处理的所有对象。获取的批次和要保存的批次大小应该是相同的数字。

【讨论】:

非常感谢您的建议。我已经按照你说的做了,这次操作期间的内存使用量下降了大约 75%,无需重新构造我的数据或将其存储在其他地方。【参考方案2】:

您的“查找”对象和相关图像之间的大小可能存在很大差异。因此,您的主要目标应该是重新设计您的数据库,使无故障(加载)Finding 对象不会自动加载 base64 编码图像。

这实际上是代码数据的主要优势之一:加载对象层次结构的一部分。只需尝试将 base64 编码数据移动到自己的(托管)对象中,这样 Core Data 就不会加载它。当引用被触摸时,它仍然会根据需要加载。

【讨论】:

以上是关于带有@autorelease和ARC的Objective C For循环的主要内容,如果未能解决你的问题,请参考以下文章

如何将 [[ivar retain] autorelease] 转换为 ARC?

2016 - 2 - 20 ARC知识总结(二 autorelease概念及实现)

NSData/CFData 桥接 @autorelease 但不是 ARC

iOS之内存管理(ARC)

在哪些情况下我们需要在 ARC 下编写 __autoreleasing 所有权限定符?

OC加强之ARC