避免NSManagedObjectContext中注册对象的积累(内存泄漏)

11

我有一个内存密集型的iOS应用程序,现在正在努力确保内存使用不会随着时间的推移而增加。我的应用程序有一个“主”上下文,它存在于应用程序的整个生命周期中,有时会为后台任务生成其他较小的上下文。

我注意到的一件事是,NSManagedObjects似乎长期注册在主上下文中,从DB中拉取对象与回收所有相关内存的唯一方法是调用[NSManagedObjectContext reset]

当然,这会导致内存使用量急剧下降,因为最近关闭的列表视图中的所有已注册对象都被正确地弹出了内存,但是这很烦人,因为您刚刚使该上下文中注册的每个对象都无效了,而您仍然拥有对其引用(即由仍然打开的视图引用的对象),现在需要重新从数据库中获取所有这些对象以避免访问无效对象时发生异常。

是否只有这种方式可以清除NSManagedObjectContext中已注册对象集,还是有更好的方式可成功弹出所有不再引用的已注册对象,但不会使所有仍活着的NSManagedObjects无效?

1个回答

14

NSManagedObjectContext有一个内部行缓存,你唯一能清空它的方式是重置上下文。如果你真正遇到了内存问题,以下几件事情可能会有所帮助:

  • 托管对象会保留与其相关的对象。如果有一个被某个托管对象B的关系引用的托管对象A,即使你释放了所有对它的引用,A仍然会保留在内存中。只有当B解除保留或重新变成fault状态时,A实际上才会被释放,因为它仍然被B保留着。
  • 应对这种(及其他内存)问题的方法之一是在当前不使用的对象上调用MOC的refreshObject:mergeChanges:方法,并将第二个参数设置为NO。这会重新声明为fault状态的对象,即使它回到最初的“fault”状态,卸载其属性值和关系。对于之前提到的AB,重新声明B为fault状态将释放与A的关系。请注意,这样会丢失B上的任何未保存更改,所以必要时确保已经保存。
  • 如果你的托管对象包含任何类型的大型二进制数据,请尝试将该数据移动到单独的实体或完全移出Core Data,以避免在不需要时将其加载到内存中。
  • 对于Core Data内存管理来说,MOC上的reset基本上是核选项。它非常有效,但正如你发现的那样,也可能非常危险。最好避免使用,除非你已经不再使用从MOC加载的任何对象了。

嘿,汤姆 - 感谢你的回复。在你提供的所有选项中,我认为唯一有用的是 refreshObject:mergeChanges:,当我在列表视图被销毁时调用它来刷新所有对象时,不幸的是它似乎没有太大的影响。我猜测行缓存正在消耗所有内存,除非有另一种清除行缓存的方法,否则我想我仍然需要使用 reset 方法。真遗憾 :( - glenc
你是否真的收到了内存警告?你没有提到过。如果没有收到,那么重置上下文是完全不必要的。 - Tom Harrington
是的,我正在收到内存警告。这取决于所使用的数据库大小,但是确实会发生。 - glenc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接