2010-10-02 112 views
0

我有一個程序讀取一個巨大的文本文件(逐行)並在將每行寫入數據庫之前對每行執行一些字符串操作。Objective-C內存泄漏了解問題

該程序需要越來越多的內存,所以我想我可能需要釋放我使用的字符串。但它沒有幫助。所以我把下面的代碼放在一起來測試實際發生的事情。隨着一些試驗和錯誤,我發現當我在自動釋放池上耗盡時,它就可以工作。

我想知道我在做什麼。所以我問:

  • 爲什麼釋放不釋放內存?
  • 有沒有更好的方法來做到這一點?

這裏是我的測試程序

#import <Foundation/Foundation.h> 

int main (int argc, const char * argv[]) { 

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

int cnt = 0; 

while (cnt < 1000000000) { 
    NSMutableString *teststr = [[NSMutableString alloc] init]; 

    teststr = [NSString stringWithString:@"Dummy string just for the demo"]; 

    cnt++; 
    if (cnt % 1000000 == 0) { 
     printf("cnt=%i\n",cnt); 
    } 

    [teststr release]; 


//  [pool drain];      // It works when I do this 
//  [[NSAutoreleasePool alloc] init]; // and this 

} 

[pool drain]; 
return 0; 
} 

編輯:基於到目前爲止,我還看着我原來的計劃,改變了測試程序的答案:

//teststr = [NSString stringWithString:@"Dummy string just for the demo"]; 

[teststr appendString:@"Dummy string just for the demo"]; 

這是否也創造一個新的字符串?因爲我仍然有內存問題。我的例程的工作原理是我在字符串後面添加了一些內容,但可能在開頭處以空字符串開頭。

回答

2
NSMutableString *teststr = [[NSMutableString alloc] init]; 

此分配一個可變的字符串....

teststr = [NSString stringWithString:@"Dummy string just for the demo"]; 

,然後這個覆蓋teststr帶有自動釋放字符串的變量。分配的可變字符串現在無法訪問,但保留計數爲+1,因此會被泄漏。

[teststr release]; 

這將只釋放自動釋放的字符串,在將來會導致雙重錯誤。


如果你想手動管理可變的字符串,你應該使用

NSMutableString* teststr = [[NSMutableString alloc] initWithString:@"Dummy string just for the demo"]; 
... 
[teststr release]; 

,不分配給teststr直接,它被釋放或所有權轉移之前。

+0

我試過了,它的工作原理。當我按照你的建議進行初始化時,我沒有記憶問題。我從一個空字符串開始,所以我這樣做了:NSMutableString \t * teststr = [[NSMutableString alloc] initWithString:@「」];但我想知道爲什麼這個工作更好,然後只是「init」。我認爲「init」也是這樣(給我一個空字符串)。無論如何感謝您的答案。 – hol 2010-10-02 11:08:12

+0

@Jürgen:是的'-init'給出一個空字符串。這並不總是更好,但是因爲你從一個已知的字符串開始,我會將init和append合併爲'-initWithString:'。 – kennytm 2010-10-02 11:11:37

+0

是的,我嘗試了一下。基本問題實際上是在我原來的程序中,我初始化了,但是然後創建了一個新的字符串,並且發佈只發布了最後一個。 – hol 2010-10-02 11:23:29

1

你犯了一個非常基本的錯誤。

  1. 你必須在你調用alloc/init時釋放一個對象。
  2. 如果您使用其他方法(構造函數,方法的返回對象等)獲取對象,則會自動釋放對象。

方法stringWithString返回一個新的自動釋放字符串,因此沒有必要分配/初始化它。此外,由於它是自動發佈的對象,因此排除自動發佈的池會有所幫助。

所以不是:

NSMutableString *teststr = [[NSMutableString alloc] init]; 
teststr = [NSString stringWithString:@"Dummy string just for the demo"]; 

試試這個:

NSMutableString *teststr = [NSString stringWithString:@"Dummy string just for the demo"]; 
0

上面的例子並不是真的有這麼多的內存問題。我的更復雜的程序「泄露」了內存,這是因爲下面的語句消耗了內存而沒有消耗。

NSString *conv = [dict objectForKey:astring]]; 

這不是一個真正的泄漏,但幾種這樣的陳述和幾十萬次的迭代引起了一個大問題。解決方案是排空autorelease池。但是,排除autorelease池的缺點是我使用的字典對象(dict)也被耗盡了。

所以這處理它。我打開第二個池:

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

NSString *conv = [dict objectForKey:astring]]; 

/* do something */ 

[pool2 drain];