【问题标题】:Core Data memory usage and Memory WarningCore Data 内存使用和内存警告
【发布时间】:2012-08-30 23:57:04
【问题描述】:

我有这个问题。 我在 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 仍然存在。

查看工具 - 分配,80MB 被许多 Malloc 使用:(示例)

图表类别 Live Bytes # Living # Transitory 总体字节数 # 总体 # 分配(净/总体) 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

有什么想法吗?谢谢

【问题讨论】:

  • 也许 Core Data 释放了 Memory Warning Level 2 的内存?您的场景是否可能导致内存不足崩溃?
  • 有什么“神奇的方法”来模拟内存警告级别 2?还是“简单地”我必须消耗内存?
  • 我不知道任何模拟方法。您应该运行另一个“重”应用程序(例如 Appstore),将您的应用程序保持在后台并跟踪控制台日志和 Instruments 内存图表。 level 2 警告将在控制台中提到 - 所以你应该在那一刻查看内存图表。
  • Mmmmhh...但是如果我将应用程序保持在后台,它将被冻结,所以我不会收到来自系统的消息,不是吗?但是我尝试了其他方法。我做了一个循环,开始浪费内存(一个简单的随机NSData数组)。我增加了总内存尝试各种数量,(尝试了很多次,有时让 iOS 杀死我的应用程序),但 Core Data 从未释放缓存:-/(显然在设备上尝试,而不是在模拟器上)
  • Mmmhh...在此链接中,文档说内存警告不会发送到暂停的应用程序:developer.apple.com/library/ios/#DOCUMENTATION/iPhone/…“当系统向您的应用程序发送低内存警告时,请立即响应。iOS只要可用内存量低于安全阈值,就会通知所有正在运行的应用程序。(它不会通知暂停的应用程序。"

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


【解决方案1】:

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

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

这样更好:

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

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

【讨论】:

  • 嘿,我只是想知道您是否找到了解决此问题的任何其他方法。不幸的是,我没有可以使用解决方案 3 的任何大的 NSData 内存对象。相反,我有数十万个在地图上显示为注释的对象。我分批获取,所以我确保如果设备没有足够的内存,我可以限制显示多少数据。但是当我收到内存警告并调用 refreshObject:mergeChanges: 内存不受影响时,我最终会遇到内存崩溃。有什么想法吗?
【解决方案2】:

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

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

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

【讨论】:

  • 是的,我应用的第一个解决方案是只获取我需要的数据。这主要是一个“学术”问题。文档对此很清楚,缓存管理是由 Core Data 完成的,所有这些都发生在幕后,但它甚至说在内存不足的情况下,内存是空闲的。我希望在内存警告后看到核心数据使用的内存减少。没有看到这个,我以为我的代码有问题......!我希望看到“用我的眼睛”Core Data 在内存不足的情况下释放内存:-)
  • 只是一个更新:我试图占用内存(分配一些 NSData 实例的简单循环),但 Core Data 从未释放内存(我尝试了很多次,分配了 100MB 的 NSData,然后是 200,然后 300 ......直到应用程序崩溃)。似乎它缓存了 fetchrequest 的所有数据而不释放它,永远不会!我知道我可以使用其他方法来达到我的范围,但这似乎很奇怪。如果继续使用 ram,故障属性是什么意思?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多