Проблема памяти основных данных - PullRequest
2 голосов
/ 18 января 2012

Я вставляю тысячи данных в мои сохраненные данные SQLite Core.Отмена управления моего ManagedObjectContext установлена ​​в ноль.Я вставляю NSManagedObject в цикл for.попытался сохранить контекст двумя способами:

1 после завершения цикла (вне цикла for).

for(int i =0;i<1000;i++){

        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d",i];
        object.age = [NSNumber numberWithInt:i];


    }

    [self managedObjectContext] save:nil];

2 для каждой вставки (внутри цикла for).

for(int i =0;i<1000;i++){

        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d",i];
        object.age = [NSNumber numberWithInt:i];
        [self managedObjectContext] save:nil];

    }

и, наконец, я вызвал сброс для ManagedObjectContext.

[[self managedObjectContext] reset];

, но проблема в том, что память, занятая для этого процесса (вставка), не возвращается после завершения.один предлагает мне, что не так с этим, или это ожидаемое поведение?Любой обходной путь для предотвращения этой утечки памяти?

ОБНОВЛЕНИЕ

Я попытался [[self managedObjectContext] refreshObject:object mergeChanges:NO]; Это может вернуть некоторый объем памяти, но не полностью. Все еще ищет хорошее решениедля управления большим объемом данных в CoreData.

Если кто-нибудь предложит мне пример проекта (исходный код), который обрабатывает большой объем данных в CoreData, тогда он будет полезен для меня.Спасибо.

Ответы [ 4 ]

2 голосов
/ 25 сентября 2014

У нас была такая же проблема в нашем проекте. Сброс контекста едва освободил память. Оказывается, проблема была исправлена ​​после сброса во всех родительских контекстах:

NSManagedObjectContext *currentContext = context;

while (currentContext) {

    [currentContext reset];
    currentContext = [currentContext parentContext];
}
1 голос
/ 18 января 2012

В вашем коде нет автозапуска пулов: D это означает, что вы храните 1000 объектов MyEntity в памяти, и это приведет к сбоям, и iOS закроет приложение (принудительное закрытие). Код должен выглядеть так:

for(int i = 0; i < 1000; i++) {
        @autoreleasepool {
                MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

                object.name = [NSString stringWithFormat:@"%d", i];
                object.age = [NSNumber numberWithInt:i];
        }
    }
    [self managedObjectContext] save:nil];

OR

for(int i = 0; i < 1000; i++) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d", i];
        object.age = [NSNumber numberWithInt:i];
        [pool drain];
    }
    [self managedObjectContext] save:nil];

Кроме того, это может быть не лучшим способом сделать подобные вещи, я бы предложил добавить его в контекст, а затем работать с самим контекстом, возможно, используя

[[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] name] = [NSString stringWithFormat:@"%d", i];

или что-то в этом роде. Таким образом, вы не создаете локальную копию объекта и не забиваете память.

Используя последний из трех методов, я бы сделал это так:

for(int i = 0; i < 1000; i++) {
        [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] name] = [NSString stringWithFormat:@"%d", i];
        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] age] = [NSNumber numberWithInt:i];
    }
    [self managedObjectContext] save:nil];

И если этот MyEntity является вашим собственным классом, вы даже можете упростить свой код с помощью

@property(nonatomic, retain) id name;
@property(nonatomic, retain) id age;

Замените id name и id age правильной переменной и классом объекта, и ваш код будет еще проще:

for(int i = 0; i < 1000; i++) {
        [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] setName: [NSString stringWithFormat:@"%d", i]];
        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] setAge: [NSNumber numberWithInt:i]];
    }
    [self managedObjectContext] save:nil];

Надеюсь, это поможет и не смущает вас!

1 голос
/ 25 мая 2013

, хотя это немного поздно,

я обнаружил, что установка undo на nil не помогла, но следующее предотвратило утечки в основных данных.

[[self managedObjectContext] processPendingChanges];  // flush operations
[[[self managedObjectContext] undoManager] disableUndoRegistration]; // disable undo

по поводу автозапуска.нажатие на исключение (в том числе на исключение числового формата) object.name = [NSString stringWithFormat:@"%d", i]; ваш пул не будет исчерпан по желанию.на самом деле, другой autoreleasepool истощит все автоматически выпущенные экземпляры.утечка памяти, например, исключение, которое создается с помощью автоматического выпуска.поэтому предлагается следующее:

NSException *myexception = nil;

try {
   .... [yadda yadda];
} catch (NSException e)
{
   myexception = [e retain];
   @throw;    
}
finally {
    [pool drain];
    [myexception release];
}

Я бы предложил не включать автозапуск, разобраться, помогает ли [[[self managedObjectContext] undoManager] disableUndoRegistration]; на меньшем наборе, а затем двигаться больше.Менеджер по отмене в основных данных - протекающая лодка, и я не нашел решение.

1 голос
/ 18 января 2012

Это вопрос автозапуска пула. Без автозапуска приложение будет сохранять память некоторое время (только парни из Apple знают, сколько времени. Если вы хотите взять процесс в свои руки, просто измените код:

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

for(int i =0;i<1000;i++){

        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d",i];
        object.age = [NSNumber numberWithInt:i];
        [self managedObjectContext] save:nil];
        [pool drain], pool = nil;
        pool =  [[NSAutoreleasePool alloc] init];
    }
 [pool drain], pool = nil;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...