2012-01-18 120 views
2

我將成千上萬的數據插入到SQLite存儲的核心數據中。 我的ManagedObjectContext的undomanager設置爲nil。 我在for循環中插入NSManagedObject。 嘗試以兩種方式保存上下文,核心數據內存問題

1完成循環後(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]; 

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的reset。

[[self managedObjectContext] reset]; 

但問題是這個過程的內存(插入)完成後沒有回來。

任何人都可以告訴我這是什麼錯誤,或者這是預期的行爲? 任何避免此內存泄漏的解決方法?

UPDATE

我試圖[[self managedObjectContext] refreshObject:object mergeChanges:NO]; 它可以放回一定數量的內存,但不fully.Still尋找在CoreData管理大量數據的一個很好的解決方案。

如果有人向我推薦一個處理大量數據的示例項目(源代碼)CoreData,那麼這對我很有幫助。 謝謝。

回答

1

這是autorelease池問題的主題。如果沒有authorelease應用程序將保持存儲一段時間(僅適用於蘋果傢伙知道,有多少時間,如果你想利用過程在你的手中,只要改變你的代碼:

NSAutoreleasePool *池= [[NSAutoreleasePool的alloc]初始化];

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; 
+0

謝謝你,讓我檢查一下我在執行 – Raj 2012-01-18 09:11:38

+0

它並不放回使用的內存 – Raj 2012-01-18 14:37:56

+0

你怎麼檢查呢? – user170317 2012-01-21 22:38:28

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]; 

希望這會有所幫助,而不會混淆你!

+0

謝謝Galaxas,讓我試試你更新 – Raj 2012-01-18 09:11:11

+0

我試過NSAutoreleasePool但它不給我使用的內存回來.. – Raj 2012-01-18 10:07:09

+0

我嘗試NSAutoreleasePool,但它不給我使用的內存back..and我找不到任何[NSEntityDescription objectForEntityForName:@「MyEntity」]方法。 – Raj 2012-01-18 10:28:44

1

雖然這是一個有點晚,

我發現,設置undonil沒有幫助,但下面確實防止核心數據泄露。

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

關於autoreleasepool。擊中一個例外(包括作爲Numberformat例外)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];是否有助於然後移動大。在覈心數據中撤銷管理員是一個漏洞問題,我還沒有想出一個解決方案。

2

我們在我們的項目中遇到了同樣的問題。重置上下文幾乎沒有釋放任何內存。原來,當復位對所有父上下文做的問題是固定的:

NSManagedObjectContext *currentContext = context; 

while (currentContext) { 

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

這工作像魅力,我只調用重置僅用於上下文和父上下文仍然持有內存。非常感謝。 – 2015-07-10 12:06:27