2012-09-06 38 views
9

我有这个问题。 我有一个核心数据中的图像数据库。 我获取所有图像(约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]); 
} 

阅读日志,我看到的物体都正确故障 然而,使用仪器,我看到的80MB的内存使用。 我认为这就是为什么Core Data会缓存结果,并在需要时释放内存。 但是(这是我的“问题”),如果我模拟内存警告,没有任何反应! 80MB仍然存在。

看着仪器 - 分配中,80MB用于许多的malloc(例如)

图分类直播字节##生活暂时性总字节数#总体#分配(净利润/总) 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 62 MB%0.00,%0.00

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

有什么想法?谢谢

+0

也许核心数据在内存警告级别2上释放内存?您的方案可能产生低内存崩溃吗? – brigadir

+0

有没有什么“魔法”来模拟内存警告等级2?或者“简单地”我必须消耗内存? – LombaX

+0

我不知道有什么模拟方法。您应该运行另一个“沉重”的应用程序(例如Appstore),将您的应用程序保持在后台并跟踪控制台日志和仪器内存图表。在控制台中会提到'2级'警告 - 所以你应该在那个时候查看内存表。 – brigadir

回答

9

好的,我明白了为什么会发生。当您为某个实体进行提取请求时,即使启用了该错误,该实体的所有数据也会加载到内存中。包括大的二进制数据。 就可以解决这个使用许多方法:

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

这样比较好:

2-你可以把你的数据拆分成不同的实体。在我的情况下,我只有2个属性:url和图像数据。我将数据分成2个实体,1:1关系:imagecache和imagedata。 对“imagecache”实体的所有行(使用url属性)进行fetchRequest,并且像以前的解决方案没有缓存内存。 propery imagecache.relationship.image是正确的错误。访问此属性会导致故障触发并缓存被填充。 但在这种情况下,在“imagecache”对象(“父”对象)上执行[self.managedObjectContext refreshObject:object mergeChanges:NO];,导致立即释放缓存和内存,从而再次出现imagecache.relationship.image属性。注意:不要在“子”对象上执行操作,因为某些原因缓存未被释放。我认为这就是为什么你要穿过这段关系。我说这主要是一个学术问题,对于这个问题真正的“全天”解决方案(更好的性能和更少的头痛)是为了避免在核心数据库中保存大数据。您可以将数据保存为文件并仅存储引用(文件路径),或者在iOS 5中,可以在核心数据模型中的任何“数据”属性上设置“使用外部存储”。这将为你做所有的工作。

+1

嘿,我只是想知道你是否曾经发现过任何其他的解决方案。不幸的是,我没有任何可以使用解决方案3的大型NSData内存对象。相反,我有成千上万的对象在地图上显示为注释。我批量提取,所以我确保如果设备没有足够的内存,我可以限制显示的数据量。但是,当我得到一个内存警告并调用refreshObject:mergeChanges:内存不会像您提到的那样受到影响,并且最终导致内存崩溃。有什么想法吗? – horsejockey

0

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

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

围绕它的方法很多;例如,使用谓词来仅选择您绝对需要的行;不要做一般性调用来获取所有内容,然后逐个浏览列表。在进行常规调用时,CoreData尝试加载所有对象时,很可能会崩溃。

+0

是的,我应用的第一个解决方案是仅提取我需要的数据。这主要是一个“学术”问题。文档清楚地表明了这一点,缓存管理由Core Data完成,并且都发生在场景后面,但它甚至表示如果内存不足,内存是免费的。我希望看到内存警告后内核数据使用的内存会减少。没有看到这一点,我在想我的代码有什么问题......!我希望看到“用我的眼睛”核心数据释放内存低内存情况:-) – LombaX

+0

只是一个更新:我试图占用内存(一个简单的循环分配一些NSData实例),但核心数据从不释放内存(我尝试了很多次,分配100MB的NSData,然后是200,然后是300,直到应用程序崩溃)。它似乎缓存了fetchrequest的所有数据而不释放它,永远不会!我知道我可以使用其他方法来达到我的范围,但这似乎很奇怪。如果他们继续使用ram,错误属性的含义是什么? – LombaX