1

I'm working on a small hobby app and am running into a weird memory issue that only occurs when I use Core Data with iCloud. If I switch the app to use a local store, the memory usage over time is just fine (usually 17-18Mb).

When I use the app with iCloud, the app continually uses more and more memory (adding about 4-5Mb every second) until it crashes.

I've done some profiling with Instruments but can't figure out a reason as to why this is happening. Does anyone have any ideas as to how to start finding a solution?

Here's a screenshot showing how much memory the app uses and how the growth is linear. The app crashes seconds after taking this screenshot.

Xcode memory usage

Here's some code from the Core Data stack setup.

    NSString *iCloudEnabledAppID = @"iCloudData";
    NSString *dataFileName = @"Moviedo.sqlite";
    NSString *iCloudDataDirectoryName = @"Data.nosync";
    NSString *iCloudLogsDirectoryName = @"Logs";
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
    NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;
    NSString *iCloudData = [[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] stringByAppendingPathComponent:dataFileName];
    NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
    NSURL *storeURL = [NSURL fileURLWithPath:iCloudData];

    NSDictionary *options = @{
                              NSMigratePersistentStoresAutomaticallyOption: @(YES),
                              NSInferMappingModelAutomaticallyOption: @(YES),
                              NSPersistentStoreUbiquitousContentNameKey: iCloudEnabledAppID,
                              NSPersistentStoreUbiquitousContentURLKey: iCloudLogsPath
                              };

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (iCloud) {

            DDLogInfo(@"iCloud is working");

            if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
                NSError *fileSystemError;
                [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
                       withIntermediateDirectories:YES
                                        attributes:nil
                                             error:&fileSystemError];
                if(fileSystemError != nil) {
                    NSLog(@"Error creating database directory %@", fileSystemError);
                }
            }

            DDLogVerbose(@"iCloudData = %@", iCloudData);

            NSError* error;
            if (! [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
                DDLogError(@"Error creating iCloud data store: %@",error);
                abort();
            }
        }
        else {
            [self setupLocalStorage];
        }
    });

Here are some screenshots from Instruments. I let the app run for about 2 minutes. Final memory usage was 453Mb. Note that I manually stopped recording, the app didn't crash.

Also there seems to be a lot of PFUbiquity* calls in the Call Tree when I opened up 3 of the top 4 Symbol Names (sorted by byte usage). Again, not really sure what I can do with this information.

Allocation Summary

Inverted Call Tree

rnystrom
  • 1,906
  • 2
  • 21
  • 47
  • 1
    With instruments, did you find which object type is being allocated? – Wain Mar 16 '14 at 20:09
  • Great question, adding some images from Instruments. I honestly can't make enough sense from the reports to take any action. – rnystrom Mar 16 '14 at 20:30
  • Have you tried setting a symbolic break point for `objc_exception_throw`? Does the crash stop somewhere interesting? – Olaf Mar 16 '14 at 22:17
  • 1
    Check out [this](http://stackoverflow.com/questions/6374159/performance-of-nsmanagedobjectcontext-save-degrades-dramatically/16618044#16618044). You may have an issue if your data model has BOTH one-to-many relationships, AND those relationships are configured with an inverse. – Rob Glassey Mar 16 '14 at 23:41
  • @RobGlassey I'd love to explore this more, but my app is pretty built up already. Plus, Xcode seems to complain about not having inverses. – rnystrom Mar 17 '14 at 02:04
  • @Olaf It just crashes with Xcode showing me an alert that says something along the lines of "App terminated due to memory issue" – rnystrom Mar 17 '14 at 02:05
  • I'm willing to bet the transaction log handling due to inverses is what is causing your problem - especially if you only see it when iCloud is in use. It's worth looking inside your iCloud store (~/Library/Mobile Documents/...) and looking to see what the iCloud transaction logs contain - they are just zipped up plists if memory serves correctly. If these files seem to be quite large, that might be an indication that this is where the problem lies. Of course, it could be something else entirely - just my gut feeling! – Rob Glassey Mar 17 '14 at 11:25

0 Answers0