13

我的问题是关于核心数据和内存没有被释放。我正在执行从返回 json 的 WebService 导入数据的同步过程。我在内存中加载要导入、循环和创建 NSManagedObjects 的数据。导入的数据需要创建与其他对象有关系的对象,总共大约有 11.000 个。但是为了隔离问题,我现在只创建第一级和第二级的项目,将关系排除在外,这些是 9043 个对象。

我开始检查使用的内存量,因为应用程序在进程结束时崩溃(使用完整的数据集)。第一次内存检查是在将 json 加载到内存中之后,因此测量实际上只考虑对象的创建和插入核心数据。我用来检查所用内存的是这段代码(source

-(无效)get_free_memory {

    结构 task_basic_info 信息;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(),
                                   TASK_BASIC_INFO,
                                   (task_info_t)&信息,
                                   &尺寸);
    如果(克尔 == KERN_SUCCESS){
        NSLog(@"正在使用的内存(以字节为单位): %f",(float)(info.resident_size/1024.0)/1024.0 );
    } 别的 {
        NSLog(@"task_info() 出错:%s", mach_error_string(kerr));
    }
}

我的设置:

  • 1 名永久存储协调员
  • 1 Main ManagedObjectContext (MMC) (NSMainQueueConcurrencyType 用于读取(只读取)app中的数据)
  • 1 后台ManagedObjectContext(BMC)(NSPrivateQueueConcurrencyType,undoManager设置为nil,用于导入数据)

BMC 独立于 MMC,因此 BMC 不是 MMC 的子上下文。他们不共享任何父上下文。我不需要 BMC 来通知 MMC 的更改。所以BMC只需要创建/更新/删除数据。

平台:

  • iPad 2 和 3
  • iOS,我已经测试将部署目标设置为 5.1 和 6.1。没有区别
  • XCode 4.6.2

问题: 导入数据,使用的内存并没有停止增加,iOS 似乎无法在进程结束后耗尽内存。如果数据样本增加,则会在应用程序关闭后导致内存警告。

研究:

  1. 苹果文档

  2. 将数据导入核心数据(Stackoverflow)时要牢记的要点

  3. 已完成测试并分析内存释放。他似乎和我有同样的问题,他发送了一份 Apple Bug 报告,Apple 尚未回复。(来源

  4. 导入和显示大型数据集(来源

  5. 表示导入大量数据的最佳方式。虽然他提到:

    “我可以在稳定的 3MB 内存中导入数百万条记录,而无需调用 -reset。”

    这让我觉得这可能以某种方式成为可能?(来源

测试:

数据样本:共创建9043个对象。

  • 关闭了关系的创建,因为文档说它们“昂贵”
  • 没有进行提取

代码:


- (void)processItems {
    [self.context performBlock:^{
        for (int i=0; i < [self.downloadedRecords count];) {
            @autoreleasepool
            {
                [self get_free_memory]; // prints current memory used
                for (NSUInteger j = 0; j < batchSize && i < [self.downloadedRecords count]; j++, i++)
                {
                    NSDictionary *record = [self.downloadedRecords objectAtIndex:i];

                    Item *item=[self createItem];
                    objectsCount++;

                    // fills in the item object with data from the record, no relationship creation is happening
                    [self updateItem:item WithRecord:record];

                    // creates the subitems, fills them in with data from record, relationship creation is turned off
                    [self processSubitemsWithItem:item AndRecord:record]; 
                }
                // Context save is done before draining the autoreleasepool, as specified in research 5)
                [self.context save:nil];

                // Faulting all the created items
                for (NSManagedObject *object in [self.context registeredObjects]) {
                    [self.context refreshObject:object mergeChanges:NO];
                }
                // Double tap the previous action by reseting the context
                [self.context reset];
            }
        }
    }];
    [self check_memory];// performs a repeated selector to [self get_free_memory] to view the memory after the sync 
}

测量:

它从 16.97 MB 变为 30 MB,在同步后下降到 28 MB。每 5 秒重复一次 get_memory 调用可将内存保持在 28 MB。

其他没有任何运气的测试:

  • 如研究 2) 所示重新创建持久存储没有效果
  • 测试让线程稍等片刻,看看内存是否恢复,示例 4)
  • 在整个过程之后将上下文设置为零
  • 完成整个过程而不在任何时候保存上下文(丢失信息)。这实际上导致维持较少的内存量,使其保持在 20 MB。但它仍然没有减少并且......我需要存储的信息:)

也许我遗漏了一些东西,但我确实进行了很多测试,在遵循指南之后,我希望看到内存再次减少。我已经运行 Allocations 工具来检查堆增长,这似乎也很好。也没有内存泄漏。

我已经没有想法可以测试/调整了......如果有人可以帮助我了解我可以测试的其他内容,或者指出我做错了什么,我将不胜感激。或者就是这样,它应该如何工作......我怀疑......

谢谢你的帮助。

编辑

我已经使用工具通过 Activity Monitor 模板来分析内存使用情况,“Real Memory Usage”中显示的结果与在控制台中打印的结果相同,get_free_memory并且内存似乎永远不会被释放。

4

2 回答 2

10

好的,这很尴尬......在方案上启用了僵尸,在参数上它们被关闭但在诊断上“启用僵尸对象”被选中......

关闭它可以保持内存稳定。

感谢那些阅读问题并试图解决它的人!

于 2013-09-03T06:53:46.357 回答
2

在我看来,您最喜欢的来源(“3MB,数百万条记录”)的关键是提到的批处理——除了禁用 Apple 推荐的非常重要的撤消管理器之外)。

我认为这里重要的是这个批处理也必须适用于@autoreleasepool

每 1000 次迭代耗尽自动释放池是不够的。您需要实际保存 MOC,然后排空池。

在您的代码中,尝试在第二@autoreleasepool个 for 循环中放入一秒钟。然后调整您的批量大小以进行微调。

我在原始 iPad 1 上对超过 500.000 条记录进行了测试。仅 JSON 字符串的大小就接近 40MB。尽管如此,这一切都没有崩溃,一些调整甚至可以带来可接受的速度。在我的测试中,我可以要求应用程序。原始 iPad 上的 70MB 内存。

于 2013-08-30T17:28:58.823 回答