-->

Core Data with iCloud causing low memory warnings

2019-08-15 01:59发布

问题:

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.

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.