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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12295415/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:25:31  来源:igfitidea点击:

Core Data memory usage and Memory Warning

objective-ciosxcodecore-datamemory-management

提问by LombaX

I have this issue. I have a database of images in Core Data. I fetch all images (about 80MB) and put in an NSMutableArray. The objects are correctly faulted:

我有这个问题。我在 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]);
}

Reading the log, I see that the objects are all correctly faulted However, using Instruments, I see that 80MB of memory are used. I think this is why Core Data caches it's results, and should free the memory when it's needed. But (and this is my "problem"), if I simulate a memory warning, nothing happens! The 80MB remains there.

阅读日志,我看到所有对象都正确出现故障 但是,使用 Instruments,我看到使用了 80MB 的内存。我认为这就是 Core Data 缓存它的结果的原因,并且应该在需要时释放内存。但是(这是我的“问题”),如果我模拟内存警告,则什么也不会发生!80MB 仍然存在。

Looking at instruments - allocations, the 80MB are used by many Malloc: (example)

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

Graph Category Live Bytes # Living # Transitory Overall 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

图类别 实时字节数 # 实时数 # 临时总字节数 # 总数 # 分配(净/总) 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

This is a link to an image of the entire Call Tree: https://www.dropbox.com/s/du1b5a5wooif4w7/Call%20Tree.png

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

Any ideas? Thanks

有任何想法吗?谢谢

采纳答案by LombaX

Ok, I've understood why it happens. When you make a fetch request for an entity, even if the faulting is enabled, ALL DATA of that entity are loaded into memory. Including big binary data. You can solve this using many methods:

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

1- setting this on your NSFetchRequest: [request setIncludesPropertyValues:NO];setting NO, the data are not loaded into the cache immediately, but only upon request (when you access the property and the fault is fired) But this have a "problem". Even if you try to fault again the propery (because you don't need it immediately and want to free the memory, using [self.managedObjectContext refreshObject:object mergeChanges:NO];), the memory is not freed. The cache stay alive until the managedObjectContext is reset.

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

This is better:

这个更好:

2- you can split your data into separate entities. In my case I had only 2 properties: an url and image data. I splitted the data into 2 entities with a 1:1 relationship: imagecache and imagedata. Made a fetchRequest for all the row of the "imagecache" entity (with the url property), and like the previous solution no memory was cached. The propery imagecache.relationship.image was correctly faulted. Accessing this property caused the fault to fire and the cache to be filled. But in this case, doing [self.managedObjectContext refreshObject:object mergeChanges:NO];on the "imagecache" object (the "father" object), resulted in immediately freeing the cache and the memory, faulting again imagecache.relationship.image property. Attention: Don't do on the "child" object, if you do [self.managedObjectContext refreshObject:object.relationship mergeChanges:NO], for some reason the cache is not freed. I think this is why you traverse the relationship.

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

3- I said this was mainly an academic question, the real "all day" solution (better performance and less headache) for this issues is to avoid saving big data inside core data database. You can save your data as files and store only a reference (filepath) or, with iOS 5 you have the possibility to set "use external storage" on any "Data" property inside your core data model. This will do all the work for you.

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

回答by prashant

I think you should load the less objects into memory in batch.

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

memory released by coredata happens behind the scenes and you don't have to program for it; the bad news is that it happens behind the scenes and thus can 'magically' chew up memory.

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

Ways around it are many; for example, use a predicate to only select the rows you absolutely must need; don't do a general call to fetch everything and then go through the list one by one. More than likely you will crash when you do the general call and CoreData attempts to load all objects.

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