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 ove开发者_开发知识库r 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?
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 objectB
, then objectA
will remain in memory even if you've released all references to it. It won't actually be deallocated until objectB
is deallocated or re-faulted, because it will still be retained byB
. - 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 toNO
. That re-faults the object, i.e. makes the object go back to the initial "fault" state, unloading its property values and relationships. WithA
andB
from before, re-faultingB
would release the relationship toA
. Keep in mind this will lose any unsaved changes onB
, 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.
精彩评论