【发布时间】:2013-09-03 10:44:06
【问题描述】:
我的问题是关于核心数据和内存没有被释放。我正在执行从返回 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 用于读取(仅读取)应用中的数据)
- 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
- ARC
问题: 导入数据,使用的内存并没有停止增加,即使在进程结束后iOS似乎也无法耗尽内存。如果数据样本增加,则会在应用程序关闭后导致内存警告。
研究:
-
苹果文档
在将数据导入 Core Data (Stackoverflow) 时要牢记的要点回顾一下
已完成测试并分析内存释放。他似乎和我有同样的问题,他发送了一份 Apple Bug 报告,Apple 尚未回复。 (Source)
导入和显示大型数据集 (Source)
-
表示导入大量数据的最佳方式。虽然他提到:
“我可以在稳定的 3MB 内存中导入数百万条记录,而无需 调用 -reset。”
这让我觉得这可能以某种方式成为可能? (Source)
测试:
数据样本:共创建 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 打印的结果相同,并且内存仍然从未出现被释放。
【问题讨论】:
-
在 Instruments 中分析内存使用情况要比使用该函数好得多。除了显示不同时间的内存使用情况外,它还将内存分配与特定的代码行联系起来。
-
此外,看起来每次通过内部循环都会处理相同的记录,因为
i在该循环期间不会更改。 -
嗨,汤姆,感谢您的回复。我已经使用用于堆增长的分配模板和泄漏模板对应用程序进行了概要分析,一切似乎都很好……您建议使用内存监视器吗?我对那个分析器不是很有经验。实际上
i在第二个循环中增加了 1(您需要滚动才能看到它,代码不完全适合框架)。这样做,我可以在@autoreleasepool块结束之前保存批次,这是我在研究 5 中读到的建议)
标签: ios objective-c core-data memory memory-management