2012-11-02 57 views
9

我们正在研究企业级应用程序,该应用程序将存储数以万计的具有核心数据的对象,并且我们在多个方面存在问题。核心数据被管理对象上下文设计建议


我们的应用程序有几个独立的系统,在需要时对数据进行操作。这些系统包括项目发现,项目加载,同步和UI显示。如果我们正确设计我们的软件,由于不同的系统修改相同的对象,应该几乎没有合并冲突。每个系统都有自己的操作队列,全部在后台执行。我们希望在后台保留所有对象的创建和修改,以最大限度地减少UI性能问题,特别是在初始阶段,可能会从服务器上的数据创建数千个对象。我们在这里尝试了各种设计,遇到了一些问题。这些斜坡上升期间巨大的内存消耗,以及所有上下文和子上下文的错误编排,导致死锁和崩溃。 我们尝试以下设计:

  • 一个根NSPrivateQueueConcurrencyType其中有一个孩子NSMainQueueConcurrencyType上下文管理对象上下文。 UI获取的结果控制器使用此子上下文从中获取结果。从NSMainQueueConcurrencyType子上下文中,我们创建了一个NSPrivateQueueConcurrencyType子上下文,我们称之为“savingContext”,每个后台操作都创建了该“savingContext”的子上下文,进行了更改,最后做了我们称之为“深度保存”的递归保存到顶部。我们最初选择这种设计时不必处理来自许多不同儿童环境的NSManagedObjectContextDidSaveNotification通知。我们将每个电话都打包到NSPrivateQueueConcurrencyType上下文中,并使用performBlockAndWait:访问对象。在功能上,这个设计进行了。所有更改和插入都保存到持久性存储中,并且UI随更改而更新。这引出了两个问题。其中一个是laggy UI,因为合并后的变化经历了NSMainQueueConcurrencyType子环境,更重要的是,在升级期间内存使用率非常高。由于无法在上下文上递归调用reset(因为主UI子上下文也存在)和/或缺乏何时调用refreshObject:mergeChanges:,所以我们会打击禁用的RAM使用。所以我们走了一条不同的道路。
  • 有两个顶级上下文与持久性存储区协调器链接,一个用于保存子上下文的NSPrivateQueueConcurrencyType和用于UI显示的NSMainQueueConcurrencyTypeNSMainQueueConcurrencyType侦听来自主NSPrivateQueueConcurrencyType上下文的NSManagedObjectContextDidSaveNotification通知,并将它们合并到主线程中。每个后台操作都创建一个主要NSPrivateQueueConcurrencyType上下文的子上下文,该子上下文也使用专用队列并发类型,执行它的操作,递归执行“深度保存”,在当前上下文上执行保存操作,深度保存到其上下文的递归调用父母,调用当前上下文重置并再次保存。这样我们可以避免内存问题,因为创建的对象在保存后会很快释放。但是,通过这种设计,我们遇到了很多问题,例如死锁,NSInternalInconsistencyException例外和提取的结果控制器不更新UI,尽管存在关于NSMainQueueConcurrencyType上下文的通知。这也会导致UI中的初始加载时间减慢很多。在之前的设计中,抓取的结果控制器返回结果的速度非常快,而这会导致UI停滞几秒,直到视图加载(我们初始化viewDidLoad中的抓取结果控制器)。

我们已经尝试了很多中间的设计,但它们都围绕着同样的问题,要么非常高的内存使用情况,获取结果控制器不更新UI或死锁和NSInternalInconsistencyException例外。


我真的很沮丧。我不禁觉得好像我们是这样设计的东西,应该是很简单的公然复杂,它只是我们缺乏了解一些基本的是杀害我们。


那么你们会建议什么?你会根据我们的情况推荐什么样的安排?我们应该如何在不同的线程中管理不同的上下文?释放插入的对象并重置上下文的最佳实践?避免死锁?所有帮助将在此时赞赏。


我也看到了MagicalRecords类别的建议。是否推荐?我们已经投入使用核心数据类型,使用MR迁移有多困难?

+0

我有类似的问题(架构之一):http://stackoverflow.com/questions/15999932/core-data-break-retain-cycle-of-the-parent-context/16008470 - 什么样的架构最后你去了吗?有小费吗? – Zyphrax

+0

我们有一个主要上下文和一个父根上下文。但根上下文仅用于保存,因此我们在每次保存时重置它。我们有很多问题。看起来,这些儿童和家长环境的新特性并没有经过深思熟虑,苹果公司仍然存在很多许多缺陷。 –

+0

我倾向于具有MOC(MainQueue)的子MOC(PrivateQueue)的体系结构,并通过添加'''[self.managedObjectContext refreshObject:self mergeChanges:NO];''''''' '我的一些ManagedObjects中的'-didSave'''。这将打破关系之间的保留周期,并允许所有MOC释放对象。只有NSPrivateQueueConcurrencyType MOCS似乎有一个奇怪的问题,他们不会解除分配的对象,但马上就下保存/回滚。 – Zyphrax

回答

6

首先,来管理你的记忆,你的第二个架构为您提供了更大的灵活性。

其次,有两种内存需要管理:malloc-ed内存和常驻VM内存。您可以拥有较低的malloc-ed内存占用空间,并且仍然拥有较大的VM驻留区域。根据我的经验,这是因为Core Data积极地坚持新插入的项目。我通过保存后修剪通知解决了这个问题。

第三,MOCS很便宜。使用他们,扔掉他们。换句话说,早期和经常释放内存。第四,尝试在主MOC上明智地做几乎没有的数据库。是的,这听起来适得其反。我的意思是,你所有的复杂查询的真的应该在后台线程来完成,然后有结果传递给主线程或具有同时利用现在填充行缓存从主线程重做查询。通过这样做,您可以保持UI的生动。第五,在我的大量多排队应用程序中,我试图让我的所有保存真的发生在后台。这使我的主要MOC保持快速并与来自网络的数据保持一致。

第六,NSFetchedResultsController是一个相当有用但专门的控制器。如果您的应用程序将其推到了其能力范围之外,它将开始锁定您的界面。当发生这种情况时,我通过自己监听-didSave通知来控制自己的控制器。

+0

感谢您的回答!锁定什么?目前,我们的应用程序不时锁定,因为我们不清楚的原因。在通知后调用'mergeChangesFromContextDidSaveNotification:'时,它通常会锁定。多个线程可以同时保存吗?上下文是否被锁定? –

+0

狮子座,我试图永远不会保存任何更改,从而最大限度地减少我的UI花费在主要MOC中的时间。即新数据从后台合并到它中。这使主要的MOC免费。此外,还要测试锁定是因为您正在更新抓取的结果控制器还是仅合并MOC。 (我打赌前者,你可以通过不设置FRC委托进行测试。)是的,多个线程可以同时保存。由于SQLite是单线程存储,所有内容都通过PSC进行序列化 - 读取也是如此。因此,我通过我的背景MOC将我的写入/保存序列化。安德鲁 – adonoho

相关问题