NSManagedObjectContext保存的性能显着降低

gle*_*enc 8 performance scalability core-data nsmanagedobjectcontext ios

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

我所看到的是,对于前8个块(44个)中的一切都进展顺利,然后性能急剧下降,每个块开始花费的时间越来越长,如下图所示.[NSManagedObjectContext save]正如您在仪器分析数据中看到的那样,几乎所有时间都消耗掉了,但似乎应用程序由于某种原因不再以100%的CPU运行,就像它正在等待磁盘I/O或其他东西一样.

分析显示性能下降的数据

关于我是如何做到的一些重要事实:

  • 每个块在其自身的处理NSManagedObjectContext与它自己的NSAutoreleasePool,所以没有对象积聚在组块的处理之间的非冲洗上下文.

  • NSUndoManager任何情境都没有设定.

  • 没有mergeChangesFromContextDidSaveNotification:进行(即块上下文没有将其更改推送到"主"上下文)

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

  • 正在编写的记录确实有索引.

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

我不知道为什么性能突然下降,或者可以采取什么措施来解决它.我已经四处寻找并阅读以下内容,但我还没有突然出现:

任何想法或指针使这个应用程序在数据库中扩展到100,000个记录将非常感激.

编辑 - 额外的统计数据

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

原始测试的磁盘活动

我还在iOS模拟器上运行了相同的同步尝试.除了包含随时间略微增长的对象ID的字典外,每个块的总内存使用量或多或少是恒定的(但这些不是CoreData对象或任何会影响保存的东西,它们只是NSNumbers).与总堆相比,此dict是少量内存,因此问题不会耗尽内存.

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

Rob*_*sey 7

我知道这是一个老问题,所以这可能不再适用于你,但它可能对其他人而言.

我已经看到了通过iCloud播种核心数据数据库的性能问题,并发现如果你在数据模型上有反向关系,那么你可能会非常严重地损害性能.iCloud事务日志记录的实现方式,实际上似乎是一个不可避免的问题.发送给iCloud的每个事务(在developer.icloud.com上查看它们 - 它们只是压缩了plist)记录了受更改影响的每个关系.与在Core Data中修改关系的一端并且负责反向结束时不同,核心数据事务日志结束时记录两个端点的更改,而不是将其解决.

因此,如果你有1对多的关系,并且你创建了另一条记录,最终会挂掉'很多'的结尾 - 那么'1'端的记录也会更新,以反映现在新的额外记录挂掉它.如果你的架构意味着你有一个"类型"对象,许多"数据"对象都会挂起,那么每次添加一个新的数据对象时,类型一个也会为它编写一个事务 - 但是这里是踢球者,因为iCloud核心数据事务记录了已编辑实体的整体状态,而不仅仅是更改,已经记录的每个关系也会添加到日志中,而不仅仅是指示新下级记录的那个.随着实体之间关系数量的增加,随着写入数据量的增加,这可能会迅速失控 - 最终需要更长时间才能保存批次.

我之前 Apple开发论坛上回答了一个类似这样的问题,这可能很有用,因为我似乎无法简洁地描述这个问题.

如果这种情况影响你,那么提高播种性能的最简单方法是关闭反向关系,但这并不总是一种选择.


jsc*_*idt 1

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