核心数据executeFetchRequest消耗大量内存

我在核心数据库中插入cca 100 000条记录。 数据库包含3个实体。 玩家,俱乐部,玩家俱乐部实体处于关系中:玩家> PlayerClub <俱乐部插入PlayerClub时,我注意到在插入大约50 000条记录后,大量内存消耗和速度损失。 记录永远不会更新,因为PlayerClub只有唯一值。 出于测试原因,我已经清空了玩家和俱乐部表并再次运行程序。 没有速度下降,但内存消耗再次巨大。 这是代码:

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基本相同,所以我发布它。 此代码被调用大约10万次。 以前的内存消耗大约是150 MB。 完成650 MB后。 因此它消耗500 MB,而不保存上下文并且不从数据库中获取任何内容导致表为空。 如果我评论

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

在DohvatiIgracZaIgracId和DohvatiKlubZaKlubId方法中,内存消耗降至200 MB。 因此,对于不执行任何操作的代码行,差异为400MB。 这不可能。 任何人都有一些想法。 一段时间后,我的应用程序消耗超过2.5 GB。

因为我需要建立一个我稍后会预加载的数据库,所以速度非常重要:)…提前了

没有保存上下文

这是经验丰富的核心数据开发人员所说的“哦,圣洁的垃圾”问题的一部分。 那是你最大的问题。 定期保存更​​改 – 每50个条目,或每100个条目,但无论你做什么, 不要等到你完成 。 您正在强制Core Data将所有这些对象保留在内存中作为未保存的更改。 这是你遇到记忆问题的最大原因。

您应该考虑的其他一些事情:

  • 不要一次取一个对象。 提取物相对昂贵。 如果你运行100k个实例并一次一个地获取它们,你的代码将花费几乎所有的时间来执行提取。 批量获取50-100(您可以调整数量以获得速度与内存使用的最佳平衡)。 处理一批,然后在批处理结束时保存更改。

  • 完成提取的对象后,告诉托管对象上下文您已完成。 通过调用refreshObject:mergeChanges:NO作为第二个参数来执行此操作。 这告诉上下文它可以释放它用于对象的任何内部存储器。 这会丢失对象上未保存的任何更改,但如果您没有进行任何更改,则没有任何损失。

  • 考虑完全摆脱PlayerClub实体。 核心数据支持多对多关系。 这种实体几乎从来没用过。 您使用的是Core Data,而不是SQL,因此不要像设计实体类型一样。