Core data 具有@autorelease和ARC的循环的目标C

Core data 具有@autorelease和ARC的循环的目标C,core-data,automatic-ref-counting,autorelease,Core Data,Automatic Ref Counting,Autorelease,作为允许审计人员创建调查结果并将照片与之关联的应用程序的一部分(由于web服务的限制,保存为Base64字符串),我必须在审计中循环检查所有调查结果及其照片,并将其同步值设置为true 当我执行这个循环时,我看到一个内存峰值从40MB左右跳到500MB(大约350张照片和255个发现),这个数字从未下降。在尝试使用此功能之前,我们的用户平均会创建1000个发现和500-700张照片。我曾尝试使用@autorelease pools来降低内存,但它似乎从未被释放 for (Finding

作为允许审计人员创建调查结果并将照片与之关联的应用程序的一部分(由于web服务的限制,保存为Base64字符串),我必须在审计中循环检查所有调查结果及其照片,并将其同步值设置为true

当我执行这个循环时,我看到一个内存峰值从40MB左右跳到500MB(大约350张照片和255个发现),这个数字从未下降。在尝试使用此功能之前,我们的用户平均会创建1000个发现和500-700张照片。我曾尝试使用@autorelease pools来降低内存,但它似乎从未被释放

    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;

        }
    }
关系和保留周期如下所示

审计与发现有着密切的关系

发现对审计的引用较弱,而对FindingPhoto的引用较强

FindingPhoto对查找的引用较弱


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

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

    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;

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

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


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

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

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

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


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

您的“查找”对象和关联图像之间的大小可能有很大差异。因此,您的主要目标应该是以某种方式重新设计数据库,以便解除(加载)查找
对象不会自动加载base64编码图像


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

您的“查找”对象和相关图像之间的大小可能有很大差异。因此,您的主要目标应该是以某种方式重新设计数据库,以便解除(加载)查找
对象不会自动加载base64编码图像


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

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