CoreData - 删除所有实体会消耗内存并且需要很长时间
CoreData - 删除所有实体会消耗内存并且需要很长时间
我有一个CoreData的配置,我在其中存储了测量数据。数据按照Session
进行分组,所以每个Session
实体与多个SensorData
实体存在一对多的关系。删除规则设置为Cascade
。我还有一个"Delete All"按钮。当按下该按钮时,我运行以下代码。
// 所有的sessions(级联删除) [self.context performBlockAndWait:^{ // 仅获取managedObjectID以减少内存影响 NSFetchRequest *sessionsRequest = [NSFetchRequest fetchRequestWithEntityName:@"Session"]; [sessionsRequest setIncludesPropertyValues:NO]; NSError *sessionsError; NSArray *allSessions = [self.context executeFetchRequest:sessionsRequest error:&sessionsError]; if (sessionsError) { NSLog(@"获取所有sessions失败。%@", sessionsError); } // 释放fetch请求 sessionsRequest = nil; // 循环删除 int i = 0; for (NSManagedObject *session in allSessions) { NSLog(@"正在删除session (%d / %d)", ++i, allSessions.count); if (i != allSessions.count) { [self.context deleteObject:session]; } } NSLog(@"所有session已删除。"); }]; NSLog(@"正在保存。"); [self.context performBlock:^{ [self.document saveToURL:self.documentPath forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success){ NSLog(@"文档保存%@。", success ? @"成功" : @"失败"); }]; }]; NSLog(@"保存完成。");
发生的情况是,我得到以下的日志输出,所以执行非常快。但是,界面会冻结,内存使用量会急剧增加。
大约有60个sessions和100万个测量数据(每个测量数据有3个浮点值),最终内存使用量太大,应用程序在大约20分钟后崩溃,所有条目仍然存在。
显然,保存过程中存在问题,但我做错了什么?非常感谢任何指点。
更新
我编辑了过程,首先删除测量数据,并设置了一个获取限制以降低内存使用量(如建议所示)。然而,如果我删除200个SensorData
,保存大约需要3秒钟,除了前大约1000个条目。删除操作很快。请参见下面的跟踪。
我希望在不删除文档的情况下解决这个问题。感觉像一个hack(虽然可能是个好主意)。
跟踪
问题的原因是在删除所有实体时,加载所有的会话数据会消耗大量的内存和时间。解决方法是按照一定数量的会话进行分批删除,以减少内存消耗和执行时间。
在原始代码中,通过执行FetchRequest将所有的会话数据加载到数组allSessions中,这会导致内存消耗大。可以尝试按照一定数量的会话进行分批加载和删除,以优化性能。
首先,创建一个NSFetchRequest对象fetchRequest,并设置fetchRequest的实体entity为"Session",同时设置fetchRequest的属性值不包含在结果中,设置fetchRequest的fetchLimit为100,即每次加载100个会话数据。
然后,通过循环执行fetchRequest来逐批加载和删除会话数据。首先执行一次fetchRequest,将加载的会话数据存储在数组items中。然后遍历items数组,逐个删除会话数据。如果删除操作成功,则保存上下文。如果保存失败,输出错误信息。
接着,再次执行fetchRequest,获取下一批会话数据。当items数组为空时,表示所有的会话数据已经删除完成。
这种方法可以有效减少内存消耗和执行时间。但是需要注意的是,由于大部分数据存储在"SensorData"实体中,而不是"Session"实体中,所以需要先删除"SensorData"实体中的数据,再删除"Session"实体中的数据。
删除"SensorData"实体数据后,保存操作可能需要较长的时间,可能是由于大量数据的删除和保存操作导致的。需要进一步分析具体原因,可能是由于数据量较大或者其他操作导致的。
以上就是解决"CoreData - delete all entities consumes RAM and take a long time"问题的原因和解决方法。通过按照一定数量的会话进行分批删除,可以减少内存消耗和执行时间,提高性能。
问题原因:删除所有实体消耗大量RAM并且需要很长时间的原因是Core Data在删除大量数据时的效率较低。
解决方法:可以使用iOS9引入的NSBatchDeleteRequest来解决这个问题。
代码示例:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"EntityName"]; NSBatchDeleteRequest *deleteRequest = [[NSBatchDeleteRequest alloc] initWithFetchRequest:fetchRequest]; NSError *deleteError = nil; [context executeRequest:deleteRequest error:&deleteError];
参考链接:[https://developer.apple.com/videos/wwdc/2015/?id=220](https://developer.apple.com/videos/wwdc/2015/?id=220)
类似问题的解答链接:[https://stackoverflow.com/questions/12113961/12116402#12116402](https://stackoverflow.com/questions/12113961/12116402#12116402)
在进行CoreData中的实体删除操作时,会消耗大量的内存并且耗时较长。这个问题的出现原因是在删除实体之前没有设置批量大小。为了解决这个问题,我们可以在获取请求中设置一个批量大小。
批量大小是指一次从持久存储中获取的对象的数量。默认值为0,表示无限制,即禁用了批量获取行为。如果设置了非零的批量大小,执行获取操作时,返回的对象集合会被分成批次。执行获取操作时,会对整个请求进行评估,并记录所有匹配对象的标识,但每次只会从持久存储中获取最多batchSize个对象的数据。执行请求后返回的数组是一个代理对象,可以根据需要透明地按需加载批次。(在数据库术语中,这是一个内存中的游标。)
你可以利用这个特性来限制应用程序中的数据工作集。结合使用fetchLimit,可以创建任意结果集的子范围。
为了线程安全起见,应该将执行获取操作后返回的数组代理视为由执行请求的托管对象上下文拥有,并将其视为在该上下文中注册的托管对象。
因此,为了解决CoreData中删除实体时消耗大量内存和耗时长的问题,我们可以在获取请求中设置批量大小,以限制一次从持久存储中获取的对象数量。