views:

40

answers:

1

I have an app that currently holds all state in memory. It fetches a bunch of information from a server as JSON and then holds on to the JSON values in memory. Each JSONObject can be ~300 bytes and there can be thousands of such objects. I use this data simply to populate UITableViews.

In order to better handle large amounts of aata, I modified my code to fetch data from the server and store it using CoreData. There JSON objects can be represented as simple entities, each with 3 NSString attributes and one 1 int32 attribute. I created a NSFetchedResultsController to use as the data source of the UITableView. My assumption was that this would reduce the resident memory usage of my application (I assume NSFetchedResults controllers effectively manages memory to not hold entities that aren't being displayed in the view, vs holding all my state in-memory). For the purposes of this discussion, let's assume my app purges the CoreData store and re-fetches all data each time it runs.

When I went to measure the changes in Resident Memory and Virtual Size using the VM Tracker in Instruments, I noticed that both these values remain almost identical. Infact, the Core-Data based version of my app seems to use more memory than when I have everything entirely in-memory.

While this may be true, I don't have an intuition for why this might be so. Any explanations? From what I have said about my app, does it sound like I don't want to bother persisting in CoreData, and why?

+2  A: 

Core Data can use more memory as you have seen, if there is memory to be had. However, one of the benefits to Core Data is when you get into a low memory situation. When that happens then Core Data will automatically reduce its own memory footprint as much as possible.

Another thing to consider is are you letting Core Data fault these objects? If you are pulling in 1000 objects and displaying 10 of them, then the other 990 should be in a faulted state and therefore taking up less memory.

I would run through the Core Data instruments and make sure you are not fulling realizing all of these objects by accident and unintentionally causing your memory usage to be higher than it needs to be.

Update

Sounds like you are importing this data and then not flushing Core Data properly if you are not seeing any faulting going on.

Assuming you are loading this data on first launch (which I would not do btw, I would pre-load the app and avoid the plist files entirely), you want to call -reset on your NSManagedObjectContext after the load is complete so that any objects that are not being used are flushed out of memory. Then as the data is coming back into memory (on use) it will be properly faulted.

Lastly, make sure you are using a SQLite store. Otherwise this is all moot.

Marcus S. Zarra
That sounds very promising - thanks Marcus. Can you please explain/provide pointers to what you mean by "fault these objects"? I suspect I'm not doing this, but I'm not sure. I save my entities and then fetch them using a NSFetchedRequestController whose NSFetchRequest has no predicate. I assume NSFetchedRequestController does the right thing but I'm too new to this to know for sure.
psychotik
Btw, I have no relationships between entities. In SQL terms, this is really just a set of simple tables with 4 columns in each row and no relational constraints.
psychotik
Hmm, I got a trace using the Core Data Instrument and I see no faults. Not sure what I need to change though - my only calls to executeFetch are via NSFetchedResultsController's `performFetch:` method. http://cid-663ff372702aa2de.office.live.com/self.aspx/Public/CoreDataInstruments.trace.zip for the trace, in case it helps.
psychotik
If you're running in the simulator, "simulate memory warning" is one way to check.
tc.
Thanks Marcus. Yes, I am using SQLite. Your update does help - calling `reset` makes rows fault in as they're made visible. Does this also mean I want to call `reset` when I receive a memory warning? I would hope the FRC would do it, but it doesn't hold on to the NSManagedContext so I don't see how it would.
psychotik
If you are displaying data in a `UITableView` you should be using a `NSFetchedResultsController` and that will also help with memory. However, if you are not using a NFRC then yes it would be useful to call reset when a memory warning is received.
Marcus S. Zarra