NSManagedObjectContext保存性能显着降低

当它试图从服务器发送的数据构build初始数据库时,我遇到了基于CoreData的iOS应用程序的问题。 基本上,服务器发送1MB大小的对象(每块大约3000个),iOS客户端将它们反序列化并将它们写入磁盘。

我所看到的是,前面的8个区块(44个区块)一切都很顺利,然后性能急剧下降,每个区块开始花费越来越长的时间,如下图所示。 几乎所有的时间都在[NSManagedObjectContext save]被使用,就像你在Instruments分析数据中看到的一样,但是由于某种原因,它似乎已经不在100%的CPU上运行,就像它正在等待磁盘I / O或者其他的东西。

分析数据显示性能下降

关于我如何做这件事的一些重要事实:

  • 每个块在自己的NSManagedObjectContext都有自己的NSAutoreleasePool ,因此在处理块之间没有对象build立在非刷新的上下文中。

  • 在任何上下文中都没有设置NSUndoManager

  • 没有mergeChangesFromContextDidSaveNotification:继续(即块的上下文没有把他们的变化推到“主”的上下文)

  • 我在iOS 4.3上使用基于SQLite的数据存储。

  • 正在写入的logging确实有索引。

  • 整个同步作业在单个GCD后台线程(即dispatch_queue_create()dispatch_async() )上处理。

我不知道为什么表演突然脱落,或者可以做些什么来解决这个问题。 我捅了一下,看了下面的内容,但是还没有什么可以跳出来的:

  • http://cocoawithlove.com/2008/03/testing-core-data-with-very-big.html

  • 保存ManagedObjectContext的性能取决于包含的(不变的)对象的数量?

任何想法或指针,使这个应用程序扩展到数据库100,000logging将不胜感激。

编辑 – 额外统计

这个Instruments图表显示了与上面相同的模拟(在iPad2上),但包括了磁盘活动统计信息,您可以很清楚地看到,所有“不在100%CPU”运行的时间似乎都被写入磁盘。

原始测试的磁盘活动

我也跑在iOS模拟器上运行相同的同步尝试。 除了包含对象ID的字典(随着时间的推移略微增长(但这些不是CoreData对象或任何会影响保存的对象,它们只是NSNumbers)),每个块的总体内存使用量或多或less是不变的。 这个字典与整个堆相比是less量的内存,所以问题不是内存不足。

这个testing的有趣之处在于CoreData Save工具报告连续保存的时间大致相同,这显然与第一组结果中的CPU分析信息冲突。 似乎CoreData认为将更改推送到数据库需要花费相同的时间,但数据库本身(即SQLite)突然花费很多时间才能将这些更改实际传输到磁盘。

我知道这是一个老问题,所以这可能不再适合你,但也可能是其他人。

我已经看到性能问题在iCloud上传播核心数据数据库,并发现如果您在数据模型上存在逆向关系,您可能会受到非常严重的性能影响。 iCloud事务日志logging的实现方式似乎是一个不可避免的问题。 每个交易发送到iCloud(在developer.icloud.com上查看它们 – 它们只是plipped压缩)logging每个受到变化影响的关系。 与在核心数据中修改关系的一端时,与核心数据事务日志相反,核心数据事务日志结束时将结束logging在两端,而不是在执行结束。

所以,如果你有一对多的关系,而且你创build了另外一个logging,这个logging最终会挂掉“多”的结尾 – 那么在'1'结尾的logging也会被更新,以反映现在新的logging挂断它。 如果你有一个体系结构,意味着你有一个“types”的对象,大量的“数据”对象挂起,那么每当你添加一个新的数据对象,types一个将有一个为它写的事务 – 但这里是kicker,因为iCloud Core Data事务logging了编辑实体的ENTIRE状态,而不仅仅是更改,已经logging的每个关系都会被添加到日志中,而不仅仅是添加新的下级logging。 随着实体间关系数量的增长,写入的数据量不断增加,这可能会快速失去控制。最终,保存批量的时间越来越长。

在苹果开发论坛上,我已经回答了一个这样的问题,这可能是有用的,因为我似乎无法简洁地描述这个问题。

如果这种情况影响到你,提高播种性能的最简单的方法是closures反向关系,但这并不总是一种select。

有关您的实施更多信息将有所帮助。 例如,你是在主线程上运行这个还是在实现后台线程? 不过,我之前看到过这种行为。 使用Core Data执行大量批处理操作时,如果内存pipe理不当,速度可能会变慢。 你有检查内存使用情况吗? 你检查了泄漏吗? 另一件要尝试的是如果需要的话,确保你正在使用NSAutoreleasePool。 通过定期排空泳池,这可能有助于performance。

Interesting Posts