核心数据内存问题

时间:2012-01-18 07:51:30

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

我将数千个数据插入到我的SQLite存储的Core数据中。 我的ManagedObjectContext的undomanager设置为nil。 我在for循环中插入NSManagedObject。 尝试以两种方式保存上下文,

完成循环后(p循环之外)

1。

for(int i =0;i<1000;i++){

        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d",i];
        object.age = [NSNumber numberWithInt:i];


    }

    [self managedObjectContext] save:nil];
每次插入

2(for循环内部)。

for(int i =0;i<1000;i++){

        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d",i];
        object.age = [NSNumber numberWithInt:i];
        [self managedObjectContext] save:nil];

    }

最后我调用了ManagedObjectContext的重置。

[[self managedObjectContext] reset];

但问题是这个过程所占用的内存(插入)在完成后没有回来。

任何人都可以告诉我这是错的,或者这是预期的行为? 避免这种内存泄漏的任何解决方法?

更新

我试过[[self managedObjectContext] refreshObject:object mergeChanges:NO]; 它可以放回一些内存,但不能完全。还可以在CoreData中搜索管理大量数据的良好解决方案。

如果有人建议我在CoreData处理大量数据的示例项目(源代码),那么对我有帮助。 谢谢。

4 个答案:

答案 0 :(得分:2)

我们的项目遇到了同样的问题。重置上下文几乎没有释放任何内存。当在所有父上下文上完成重置时,问题得到解决:

NSManagedObjectContext *currentContext = context;

while (currentContext) {

    [currentContext reset];
    currentContext = [currentContext parentContext];
}

答案 1 :(得分:1)

这是自动发布池问题的主题。没有authorelease应用程序将保留内存一段时间(只有苹果人知道,多少时间。如果你想在你的手中采取过程,只需更改你的代码:

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

for(int i =0;i<1000;i++){

        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d",i];
        object.age = [NSNumber numberWithInt:i];
        [self managedObjectContext] save:nil];
        [pool drain], pool = nil;
        pool =  [[NSAutoreleasePool alloc] init];
    }
 [pool drain], pool = nil;

答案 2 :(得分:1)

你的代码缺少autoreleasepools:D这意味着你将1000个MyEntity对象存储在内存中,这将导致崩溃,iOS将FC你的应用程序(强制关闭)。代码应如下所示:

for(int i = 0; i < 1000; i++) {
        @autoreleasepool {
                MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

                object.name = [NSString stringWithFormat:@"%d", i];
                object.age = [NSNumber numberWithInt:i];
        }
    }
    [self managedObjectContext] save:nil];

OR:

for(int i = 0; i < 1000; i++) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        object.name = [NSString stringWithFormat:@"%d", i];
        object.age = [NSNumber numberWithInt:i];
        [pool drain];
    }
    [self managedObjectContext] save:nil];

此外,这可能不是做这种事情的最佳方式,我建议将其添加到上下文中,然后使用

操作上下文本身

[[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] name] = [NSString stringWithFormat:@"%d", i];

或类似的东西。这样您就不会创建对象的本地副本并堵塞内存。

使用三种方法中的最后一种,我会这样做:

for(int i = 0; i < 1000; i++) {
        [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] name] = [NSString stringWithFormat:@"%d", i];
        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] age] = [NSNumber numberWithInt:i];
    }
    [self managedObjectContext] save:nil];

如果此MyEntity是您自己的自定义类,您甚至可以使用

简化代码
@property(nonatomic, retain) id name;
@property(nonatomic, retain) id age;

id nameid age替换为正确的变量和对象类,这样您的代码就更简单了:

for(int i = 0; i < 1000; i++) {
        [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];

        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] setName: [NSString stringWithFormat:@"%d", i]];
        [[NSEntityDescription entityForName:@"MyEntity"  inManagedObjectContext:managedObjectContext] setAge: [NSNumber numberWithInt:i]];
    }
    [self managedObjectContext] save:nil];

希望这会有所帮助,不会让您感到困惑!

答案 3 :(得分:1)

虽然这有点晚了,

我发现将undo设置为nil没有帮助,但以下确实可以防止核心数据泄露。

[[self managedObjectContext] processPendingChanges];  // flush operations
[[[self managedObjectContext] undoManager] disableUndoRegistration]; // disable undo

关于自动释放池。点击异常(包括数字格式例外)object.name = [NSString stringWithFormat:@"%d", i];您的池将不会根据需要耗尽。事实上,另一个autoreleasepool将耗尽所有自动释放的实例。内存将泄漏,例如通过autorelease创建的异常。所以建议如下。

NSException *myexception = nil;

try {
   .... [yadda yadda];
} catch (NSException e)
{
   myexception = [e retain];
   @throw;    
}
finally {
    [pool drain];
    [myexception release];
}

我建议不要放入autoreleasepool,理清[[[self managedObjectContext] undoManager] disableUndoRegistration];是否有助于较小的集合然后移动更大。核心数据中的撤销管理器是一个漏洞,我还没有想出解决方案。