0

在此处输入图像描述

这就是我通过仪器运行我的应用程序时得到的。它正在处理大量核心数据。我可以看到这显然是不对的,但我真的不知道这个屏幕截图告诉我什么。似乎是什么问题?如果您有兴趣,浓缩后的代码是这样的:

    NSFetchRequest *oldFetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *oldEntryEntity = [NSEntityDescription entityForName:@"Entry"
                                                      inManagedObjectContext:oldContext];

    [oldFetchRequest setEntity:oldEntryEntity];

    int numberOfEntries = [oldContext countForFetchRequest:oldFetchRequest error:nil];

    int batchSize = 4;
    [oldFetchRequest setFetchLimit:batchSize];
    int offset = 0;

    while (numberOfEntries - offset > 0) {
        @autoreleasepool {
        [oldFetchRequest setFetchOffset:offset];
        NSError *error;
        NSArray *entries = [oldContext executeFetchRequest:oldFetchRequest error:&error];

        for (NSManagedObject *entry in entries) {
        @autoreleasepool {
            Entry *newEntry = [NSEntityDescription insertNewObjectForEntityForName:@"Entry"
                                                            inManagedObjectContext:newContext];

            newEntry.entryID = [entry valueForKey:@"entryID"];

            NSMutableOrderedSet *newMediaSet = [[NSMutableOrderedSet alloc] init];

            NSOrderedSet *mediaSet = [entry valueForKey:@"media"];

            int i = 0;

            for (NSManagedObject *media in mediaSet) {

                Media *newMedia = [NSEntityDescription insertNewObjectForEntityForName:@"Media"
                                                                inManagedObjectContext:newContext];

                newMedia.isInPhotoLibrary = [media valueForKey:@"isInPhotoLibrary"];
                newMedia.positionInEntry = [NSNumber numberWithDouble:i + 1];

                MediaImageData *imageData = [NSEntityDescription insertNewObjectForEntityForName:@"MediaImageData"
                                                                          inManagedObjectContext:newContext];

                imageData.data = [media valueForKey:@"originalImage"];

                newMedia.imageData = imageData;

                newMedia.entry = newEntry;
                [newMediaSet addObject:newMedia];

                i++;
            }

            newEntry.media = newMediaSet;


        }
        }

        [newContext save:&error];

        offset = offset + batchSize;
   }
}

编辑:我按照这里给出的建议,将它包装在@autoreleasepools(我已经在上面编辑过)中,发生这种情况后它仍然崩溃:

http://cl.ly/image/1U2T2p3w1X2Z

它显然比第一次更深入代码,但它仍然崩溃。

4

3 回答 3

2

不讨论代码的效率:将代码
包装在@autoreleasepool {}外部(while)和内部(for)循环中。
否则,您只是分配大量内存并仅在外部事件循环到达循环结束时释放它。

于 2012-09-17T12:25:18.493 回答
1

首先,关于发布 Core Data 相关问题的一些建议。几乎没有太多的信息。当你省略细节时,人们很难帮助你,因为可能的互动太多了。

只看你发布的代码,它留下了很多问题。

我想查看按总体大小排序的信息,而不是按分配数量排序的信息。这将更容易地告诉您内存在哪里使用。事实上,我看不到那张照片中的记忆在哪里使用(然后再次 - 老眼睛 - 当我放大它时,它变得太模糊了)。

如果您认为它与核心数据有关,为什么不运行核心数据工具?

获得一些诊断帮助。

您的新 MOC 是直接连接到 PSC 还是有父 MOC。如果它有一个父 MOC,那么保存只是被推到父 MOC 中,并且将保留在内存中,直到保存被持久化到数据库中。

您的 mediaSet 中有多少项目?可能有很多这些,这可能会占用内存。

您对 FetchRequest 和 MOC 应用了哪些参数?基于这些选项,MOC 可以保留对象。检查这一点的一种方法是记录每个 MOC 的保留/插入/删除/等集的计数。通过记录这些,您可以查看任何一个 MOC 是否持有您认为不应该持有的东西。

然后你可以知道你是否需要刷新/重置你的 MOC。

您可以作弊,并[moc reset]在保存后调用,但最好在这样做之前/之后查看数字,这样您就可以说服自己内存在哪里。

做更多的调试。给自己更多的信息,这样你就可以做出正确的决定……它也会给我们更好的信息来帮助你。

编辑

哎呀。我删除了关于可能没有太多内存的评论。看着那张照片上的小字,我的老眼睛对我毫无帮助。

编辑

谢谢。如何记录每个 MOC 的保留/插入/删除集的计数?- 安德鲁

MOC 有几个属性(registeredObjectsinsertedObjectsdeletedObjectsupdatedObjects),它们提供了一组与这些类别匹配的对象。只需NSLog计算每个类别中的对象数。您可以看到,对于每个 MOC,随着时间的推移 MOC 正在跟踪多少对象。

此外,启用核心数据工具。他们真的很翔实。

于 2012-09-17T15:42:19.283 回答
1

尝试将快速枚举(for循环)的内部包装在 中@autoreleasepool,这应该会有所帮助。当更改达到危险的内存消耗时,您还可以运行某种计数器以将上下文保存在循环中。

不过,您确实有很多对象,请考虑优化您的数据结构。

于 2012-09-17T12:24:49.570 回答