关于Core Data和内存无法释放的问题。我的问题是在从返回JSON的WebService中导入数据时进行同步处理。我将要导入的数据加载到内存中,循环遍历并创建NSManagedObjects。导入的数据需要创建与其他对象关联的对象,在总共大约11,000个对象中,但为了隔离问题,我现在只创建第一层和第二层的项目,而不考虑关系,这些是9043个对象。
我开始检查使用的内存量,因为应用程序在进程结束时崩溃(具有完整数据集)。第一个内存检查是在将json加载到内存后,因此测量真正只考虑了对象的创建和插入到Core Data中。我用于检查使用的内存是这段代码(来源)
-(void) get_free_memory {
struct task_basic_info info; mach_msg_type_number_t size = sizeof(info); kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); if( kerr == KERN_SUCCESS ) { NSLog(@"Memory in use (in bytes): %f",(float)(info.resident_size/1024.0)/1024.0 ); } else { NSLog(@"Error with task_info(): %s", mach_error_string(kerr)); } }
我的设置:
- 1 持久存储协调者
- 1 主要托管对象上下文(MMC)(使用NSMainQueueConcurrencyType仅用于在应用程序中读取数据)
- 1 后台托管对象上下文(BMC)(NSPrivateQueueConcurrencyType,undoManager设置为nil,用于导入数据)
BMC独立于MMC,因此BMC不是MMC的子上下文。它们也不共享任何父上下文。我不需要BMC通知MMC进行更改。因此,BMC只需要创建/更新/删除数据。
平台:
- iPad 2和3
- iOS,我已将部署目标设置为5.1和6.1。没有区别
- XCode 4.6.2
- ARC
问题: 导入数据时,使用的内存不停地增加,并且iOS似乎无法释放内存,即使在处理结束后。如果数据样本增加,这将导致内存警告并在关闭应用程序后。
研究:
Apple文档
这是一个很好的回顾,在将数据导入到Core Data时需要考虑的要点。(来源:Stackoverflow)
进行的测试和内存释放分析。他似乎和我有同样的问题,并向苹果发送了错误报告,但尚未收到回复。(来源:Source)
导入并显示大型数据集(来源:Source)
指出了导入大量数据的最佳方法。虽然他提到:
"我可以在稳定的3MB内存中导入数百万条记录,而无需调用-reset."
这让我认为这可能是可能的?(来源:Source)
测试:
数据样本:创建总共9043个对象。
- 关闭关系的创建,因为文档中说它们是“昂贵”的
- 没有进行任何获取操作
代码:
- (void)processItems { [self.context performBlock:^{ for (int i=0; i < [self.downloadedRecords count];) { @autoreleasepool { [self get_free_memory]; // 显示当前内存使用情况 for (NSUInteger j = 0; j < batchSize && i < [self.downloadedRecords count]; j++, i++) { NSDictionary *record = [self.downloadedRecords objectAtIndex:i]; Item *item=[self createItem]; objectsCount++; // 从record中填充项对象的数据,不创建关系 [self updateItem:item WithRecord:record]; // 创建子项,从record中填充数据,并关闭关系创建 [self processSubitemsWithItem:item AndRecord:record]; } // 在释放自动释放池之前执行上下文保存,如研究5)所述 [self.context save:nil]; // 将所有已创建的项反归为虚址状态 for (NSManagedObject *object in [self.context registeredObjects]) { [self.context refreshObject:object mergeChanges:NO]; } // 重置上下文,以二次执行前面的操作 [self.context reset]; } } }]; [self check_memory];// 通过多次调用 [self get_free_memory] 方法查看同步后内存情况 }
测量:
同步前,内存从16.97 MB到30 MB之间波动,同步后下降至28 MB。每5秒重复调用get_memory函数可将内存保持在28 MB。
其他尝试但没有成功的测试:
- 按照研究2)中的指示重新创建持久化存储区域无效
- 尝试让线程等待一段时间以查看内存是否恢复,例如第4个例子
- 在整个过程结束后将上下文设置为nil
- 在任何时候都不保存上下文完成整个过程(因此失去信息)。实际上,这产生了保持少量内存的结果,将其保持在20 MB左右。但它仍然不会减少...我需要存储的信息 :)
也许我错过了什么,但我真的测试了很多次,按照指南进行操作后,我希望再次看到内存减少。我已经运行了分配工具来检查堆增长,这也似乎没问题。也没有内存泄漏。
我正在思考要测试/调整的想法...如果有人能帮我提出其他测试的想法,或者指出我做错了什么,我将非常感激。或者它就像这样,应该这样工作...我怀疑...
谢谢任何帮助。
编辑
我使用工具来使用Activity Monitor模板分析内存使用情况,并且在“实际内存使用情况”中显示的结果与使用
get_free_memory
打印到控制台中的结果相同,但内存似乎仍然没有被释放。
i
不会改变。 - Tom Harringtoni
每次递增1(您需要滚动查看,代码无法完全适应框架)。这样做,我能够在@autoreleasepool
块结束之前保存批处理,这是我在Research 5)中读到的建议。 - Tamara Bernad