Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding registered object buildup (memleak) in NSManagedObjectContext

I have a memory-intensive iOS app and I'm working on making sure that memory usage does not build up over time. My app has a "main" context that lives for the lifetime of the app, with other smaller contexts being spawned occasionally for background tasks.

One thing I have noticed is that NSManagedObjects appear to remain registered in the main context long-term and the only way to truly reclaim all the memory associated with pulling the objects from the DB is to call [NSManagedObjectContext reset].

This of course results in a nice drop in memory usage as all the registered objects from recently closed list views are properly ejected from memory, however it is annoying because you have just invalidated every object that was registered in that context that you still have a reference to (i.e. objects that are refered to by views that are still open), and you now need to re-fetch all the these objects from the database to avoid exceptions for accessing an invalidated object.

Is this the only way of flushing out the registered object set from an NSManagedObjectContext, or is there a better way that successfully ejects all the registered objects you no longer have references to, but doesn't invalidate all the NSManagedObjects that are still alive?

like image 345
glenc Avatar asked Jun 21 '11 20:06

glenc


1 Answers

NSManagedObjectContext has an internal row cache, and the only way you can clear that out is by resetting the context. If you're actually experiencing memory issues, a few things that may help are:

  • Managed objects retain their related objects. If you have managed object A that's referenced by a relationship from some other managed object B, then object A will remain in memory even if you've released all references to it. It won't actually be deallocated until object B is deallocated or re-faulted, because it will still be retained by B.
  • One way of dealing with this (and other memory issues) is by calling refreshObject:mergeChanges: on the MOC for objects you aren't currently using, with the second argument set to NO. That re-faults the object, i.e. makes the object go back to the initial "fault" state, unloading its property values and relationships. With A and B from before, re-faulting B would release the relationship to A. Keep in mind this will lose any unsaved changes on B, so make sure you've saved first if necessary.
  • If your managed objects contain any kind of large binary data, try moving that data into a separate entity or out of Core Data altogether to avoid loading it into memory when it's not needed.
  • reset on the MOC is basically the nuclear option when it comes to Core Data memory management. It's extremely effective but as you've found can be very dangerous. It's best avoided unless you already aren't using any objects loaded from the MOC.
like image 91
Tom Harrington Avatar answered Nov 15 '22 20:11

Tom Harrington