2010-10-02 89 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];