1

I am calling refreshObject:mergeChanges:NO on my objects to turn them into faults, after I call save on the Managed Object Context. However, this is creating a spike in memory usage.

I'm trying to turn the objects into faults, in order to break the reference cycles so that memory can be freed up.

Without calling refreshObject my application is able to run for 30-40 mins before it is killed for consuming too much ram. However, if I call it after each context save, then it lasts barely a few minutes.

This is my Core Data stack:

# Persistent Store Coordinator <--+-- privateWriterContext (NSPrivateQueueConcurrencyType)
#                                            |
#                                            +----- defaultManagedObjectContext (NSMainQueueConcurrencyType) # for the main thread
#                                                   |
#                                                   +----- backgroundManagedObjectContext (NSPrivateQueueConcurrencyType) # for bg tasks

This is the code I am using to persist and then refreshObject

if privateWriterContext.MR_saveToPersistentStoreAndWaitWithError(error)
    privateWriterContext.performBlockAndWait(
      lambda {
        privateWriterContext.registeredObjects.each do |object|
          privateWriterContext.refreshObject(object, mergeChanges: false)
        end
      }.weak!
    )
else
  # handle error
end

I have read through other Stackoverflow questions where other people appear to have implemented refreshObject successfully:

And this is the relevant snippet of Apple's Object Lifetime Management documentation:

When you have relationships between managed objects, each object maintains a strong reference to the object or objects to which it is related. This can cause strong reference cycles. To ensure that reference cycles are broken, when you're finished with an object you can use the managed object context method refreshObject:mergeChanges: to turn it into a fault.

Community
  • 1
  • 1
Paul Sturgess
  • 3,254
  • 2
  • 23
  • 22
  • You are refreshing the objects only in the private context. They might still be alive (and taking memory) in the main thread context. The main thread displays the data from managed objects, so it has to load the data from the persistent store into the memor. Does calling `refreshObject` on main context's registered objects help? – Michał Ciuba Jan 13 '15 at 21:19
  • I have a tried a few combinations of refreshing or not refreshing on either the privateWriterContext or my defaultManagedObjectContext – I can see the numbers of registeredObjects drop to zero. But it still just speeds up the unbounded memory growth. – Paul Sturgess Jan 13 '15 at 21:24

1 Answers1

1

I fixed this by removing all usage of performBlockAndWait and switched to using performBlock instead.

I then used NSNotificationCenter to send a message when the save had completed.

Paul Sturgess
  • 3,254
  • 2
  • 23
  • 22