2013-11-13 4 views
4

Я ввожу около 100 000 записей в базу данных данных ядра. База данных содержит 3 объекта. игрок, клуб, PlayerClub Сущность в отношениях: игрок < - >> PlayerClub < < -> Клуб При вставке в PlayerClub я заметил много потребления памяти и потерю скорости после того, как около 50 000 записей были вставлено. Записи никогда не обновляются, потому что PlayerClub имеет только уникальные значения. По причинам тестирования я освободил таблицы игроков и клуба и снова запустил программу. Не было снижения скорости, но потребление памяти снова было огромным. Это код:Основные данные executeFetchRequest потребляет огромные объемы памяти

NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; 
    [context setPersistentStoreCoordinator:ap.persistentStoreCoordinator]; 
    [context setUndoManager:nil]; 

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"PlayerClub" 
               inManagedObjectContext:context]; 

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    [request setEntity:entity]; 

    NSEntityDescription *entityKlubovi = [NSEntityDescription entityForName:@"Club" inManagedObjectContext:context]; 
    NSFetchRequest *requestKlubovi = [[NSFetchRequest alloc] init]; 
    [requestKlubovi setEntity:entityKlubovi]; 
    [requestKlubovi setFetchLimit:1]; 

    NSEntityDescription *entityIgraci = [NSEntityDescription entityForName:@"Player" inManagedObjectContext:context]; 
    NSFetchRequest *requestIgraci = [[NSFetchRequest alloc] init]; 
    [requestIgraci setFetchLimit:1]; 
    [requestIgraci setEntity:entityIgraci]; 

    for (int i=0; i<[parsedKlubIgraci count]; i++) { 
     @autoreleasepool { 
      KlubIgrac *klubIgrac = [[KlubIgrac alloc] initWithEntity:entity insertIntoManagedObjectContext:context]; 

      klubIgrac.iD = p.id; 

      //... add some othe properties 

      variables = [NSDictionary dictionaryWithObject:p.igracID forKey:@"ID"]; 
      localPredicate = [predicateIgraci predicateWithSubstitutionVariables:variables]; 
      [requestIgraci setPredicate:localPredicate]; 
      klubIgrac.igrac = [self DohvatiIgracZaIgracId:p.igracID cntx:context request:requestIgraci predicate:localPredicate]; 

      variables = [NSDictionary dictionaryWithObject:p.klubID forKey:@"ID"]; 
      localPredicate = [predicateKlubovi predicateWithSubstitutionVariables:variables]; 
      [requestKlubovi setPredicate:localPredicate]; 
      klubIgrac.klub = [self DohvatiKlubZaKlubId:p.klubID cntx:context request:requestKlubovi predicate:localPredicate]; 
     } 

    } 
+(Club *)DohvatiKlubZaKlubId:(int)klubid cntx:(NSManagedObjectContext *)context  

    request:(NSFetchRequest *)request predicate:(NSPredicate *)predicate 
{ 
    @autoreleasepool { 
     NSError *error; 
     NSArray *arTmp; 
     arTmp = [context executeFetchRequest:request error:&error]; 
     Club *klub; 
     if(arTmp != nil && [arTmp count]){ 
      return [arTmp objectAtIndex:0]; 
     } 
    } 

} 

метод DohvatiIgracZaIgracId в основном тот же метод, как DohvatiKlubZaKlubId поэтому я dinnt разместить его. Этот код называется около 100 000 раз. Потребление памяти до этого составляет около 150 МБ. После того, как он закончит его 650 МБ. Поэтому он потребляет 500 МБ, не сохраняя контекста и не извлекая ничего из базы данных, потому что эти таблицы пустые. Если я комментирую

arTmp = [context executeFetchRequest:request error:&error]; 

линии в DohvatiIgracZaIgracId и DohvatiKlubZaKlubId методы потребление памяти падает до 200 МБ. Таким образом, разница составляет 400 МБ для строки кода, которая ничего не делает. Это не может быть. У кого-то есть идеи. Через некоторое время мое приложение потребляет более 2,5 ГБ.

В mesuments были сделана на тренажер причине мне нужно создать базу данных, что я подожму позже, поэтому скорость имеет значение:) ... Thx заранее

+0

Возможно, вам стоит обратиться к пакетной обработке для CoreData. – Jonathan

+0

Но мой лимит выборки равен 1, зачем мне нужно использовать пакет? – AntonijoDev

+0

Ok Я установил setFetchBatchSize в 1 для обоих запросов, а O выиграл 50 МБ. Не могу объяснить, почему, но я сделал, но все же 450 - это много :) – AntonijoDev

ответ

10

без сохранения контекста

Это часть вопроса, где опытные разработчики Core Data говорят «о, святое дерьмо». Это ваша самая большая проблема. Сохраняйте изменения с регулярными интервалами - каждые 50 записей или каждые 100, но независимо от того, что вы делаете, не ждите, пока вы не закончите. Вы вынуждаете Core Data сохранять все этих объектов в памяти как несохраненные изменения. Это самая большая причина, по которой у вас проблемы с памятью.

Некоторых другие вещи, которые вы должны рассмотреть следующие вопросы:

  • не забирает ваши объекты один за один раз. Выборы относительно дороги. Если вы запускаете экземпляры 100k и выбираете каждый из них по одному, ваш код будет тратить почти все свое время на выполнение выборки. Выбирайте партии по 50-100 (вы можете настроить номер, чтобы получить наилучший баланс скорости и памяти). Обработайте одну партию, а затем сохраните изменения в конце партии.

  • Когда вы закончите с выбранным объектом, расскажите об управляемом объекте, который вы сделали. Сделайте это, вызвав refreshObject:mergeChanges: с NO в качестве второго аргумента. Это говорит о том, что он может освободить любую внутреннюю память, которую он использует для объекта. Это теряет любые несохраненные изменения на объектах, но если вы не внесли никаких изменений, вам нечего терять.

  • Рассмотрите возможность полного удаления объекта PlayerClub. Основные данные поддерживают отношения «многие ко многим». Этот тип сущности почти никогда не бывает полезен. Вы используете Core Data, а не SQL, поэтому не создавайте типы объектов, как если бы вы были.

+0

Хороший ответ. В сочетании с этой запиской: «Вы используете Core Data, а не SQL, поэтому не создавайте типы объектов, как если бы вы были». Я думаю, что важно добавить, что Core Data не является реляционной базой данных. Это граф объектов. – Jonathan

+0

Справа. Он ** использует ** SQLite, но это деталь реализации. API Core Data очень отличается от SQLite. –

+0

Я сохраняю каждые 100 записей (в моем исходном коде). Проблема в том, что мне приходится строить отношения во время разбора. Это то, что я делаю: – AntonijoDev

Смежные вопросы