核心数据内存使用和内存警告

时间:2012-09-06 07:56:09

标签: objective-c ios xcode core-data memory-management

我有这个问题。 我在Core Data中有一个图像数据库。 我获取所有图像(大约80MB)并放入NSMutableArray。 这些对象是错误的:

NSArray *fetchResults = [self.managedObjectContext executeFetchRequest:request error:&error];
self.cache = [NSMutableArray arrayWithArray:fetchResults];
for (ImageCache *imageObject in self.cache) {
    NSLog(@"Is fault? %i", [imageObject isFault]);
}

阅读日志,我发现对象都是正确的错误 但是,使用Instruments,我看到使用了80MB的内存。 我认为这就是为什么Core Data会缓存它的结果,并且应该在需要时释放内存。 但是(这是我的“问题”),如果我模拟一个内存警告,没有任何反应! 80MB仍在那里。

查看仪器 - 分配,许多Malloc使用80MB :(示例)

图表类别实时字节#Living#Transitory Total Bytes#Overall #Allocations(Net / Overall) 0 Malloc 176,00 KB 8,59 MB 50 57 18,39 MB 107%0.00,%0.00 0 Malloc 200,00 KB 8,20 MB 42 460 98,05 MB 502%0.00,%0.04 0 Malloc 168,00 KB 7,05 MB 43 19 10,17 MB 62%0.00,%0.00

这是指向整个调用树图像的链接:https://www.dropbox.com/s/du1b5a5wooif4w7/Call%20Tree.png

有什么想法吗?感谢

2 个答案:

答案 0 :(得分:9)

好的,我已经明白为什么会这样。当您对实体进行获取请求时,即使启用了错误操作,该实体的所有数据也会加载到内存中。包括大二进制数据。 您可以使用许多方法解决此问题:

1-在NSFetchRequest [request setIncludesPropertyValues:NO];上设置此项 设置为NO,数据不会立即加载到缓存中,而是仅在请求时(当您访问属性并触发故障时) 但这有一个“问题”。即使你试图再次故障(因为你不需要它立即想要释放内存,使用[self.managedObjectContext refreshObject:object mergeChanges:NO];),内存也不会被释放。缓存保持活动状态,直到重置managedObjectContext。

这样更好:

2-您可以将数据拆分为单独的实体。在我的情况下,我只有2个属性:网址和图像数据。我将数据拆分为2个实体,关系为1:1:imagecache和imagedata。 为“imagecache”实体的所有行(使用url属性)创建了一个fetchRequest,就像之前的解决方案一样,没有缓存内存。属性imagecache.relationship.image是正确的错误。访问此属性会导致触发故障并填充缓存。 但在这种情况下,对“imagecache”对象(“父”对象)执行[self.managedObjectContext refreshObject:object mergeChanges:NO];会导致立即释放缓存和内存,再次出现imagecache.relationship.image属性。注意:如果执行[self.managedObjectContext refreshObject:object.relationship mergeChanges:NO],请不要对“child”对象执行操作,由于某种原因,不会释放缓存。我认为这就是你追踪这段关系的原因。

3-我说这主要是一个学术问题,这个问题的真正“全天”解决方案(更好的性能和更少的头痛)是避免在核心数据库中保存大数据。您可以将数据保存为文件并仅存储引用(文件路径),或者使用iOS 5,您可以在核心数据模型中的任何“数据”属性上设置“使用外部存储”。这将为您完成所有工作。

答案 1 :(得分:0)

我认为您应该将较少的对象批量加载到内存中。

coredata发布的记忆发生在幕后,你不必为它编程;坏消息是它发生在幕后,因此可以“神奇地”发生。咀嚼记忆。

周围的方式很多;例如,使用谓词只选择你绝对需要的行;不要进行一般性调用以获取所有内容,然后逐个浏览列表。当您进行一般调用并且CoreData尝试加载所有对象时,您很可能会崩溃。