1

我有一个奇怪的(在我看来)和使用 ARC(自动引用计数)的简单内存泄漏情况。我正在使用 iOS 代码,但我认为它应该普遍适用于 Objective-C。


我有一个以下函数,它在检查参数对象的属性后返回作为参数分配的对象。

- (id) returnParam:(id) obj
{
    // Do whatever filtering needed. Return nil for invalid input.

    return (NSNumber *)obj;
}

如果我在循环中调用此方法,如下所示,我可以看到分配的内存不断增加,直到循环在 Instruments 中结束。

for(int i = 0; i < 1000000; i++)
{        
    id obj = [[NSNumber alloc] initWithInt:i];        
    id obj2 = [self returnParam:obj];
    NSLog(@"attempt %@", obj2);
}


但是,如果我将returnParam函数的内容按如下方式放入循环中,则一切正常。内存脚印一直保持相同的大小。

for(int i = 0; i < 1000000; i++)
{        
    id obj = [[NSNumber alloc] initWithInt:i];

    // Do whatever filtering needed. Break on invalid input.

    id obj2 = obj;

    NSLog(@"attempt %@", obj2);
}


我已经消除了过滤部分(所以基本上该函数只将对象传递回调用者),同样的情况仍然存在。


不明白为什么这个序列不会像假设的那样减少保留计数,我尝试了所有可能的组合__weak__unsafe_unretained这里和那里,但没有一个有效。

有人可以解释为什么这个(返回参数对象)不起作用,并建议我解决这个问题吗?


PS BTW,它没有被捕获为仪器中的内存泄漏事件,但我认为的情况是明显的内存泄漏。

4

1 回答 1

3

这不是泄漏。它与如何-autorelease工作有关。扩展什么-returnParam:

-(id) returnParam:(id) paramToReturn
{
   // make sure the variable is in the scope for the entirety of the function
   id returnValue = nil;
   @try 
   {
       // when the parameter is passed in, ARC will automatically retain it.
       [paramToReturn retain];
       returnValue = [paramToReturn retain]; // strong assignment (a = b)
       return returnValue;
   }
   @finally
   {
       [paramToReturn release]; // release the value we retained when we passed in the parameter
       [returnValue autorelease]; // autorelease the return value so it is still valid after the function exits.
   }
}

现在,让我们将其与您的另一个循环进行比较:

for (int i = 0; i < 1000; i++)
{
    id obj = [[NSNumber numberWithInt:i] retain]; // retain, because 'obj' is strong by default.
    id obj2 = [obj retain]; // retain, because 'obj2' is strong by default

    NSLog(@"attempt %@", obj2);

    [obj release]; // release because 'obj' is strong
    [obj2 release]; // release because 'obj2' is strong.
}

因此,在弹出下一个 autorelasepool 之前,您的变量不会被清理,这通常发生在 iPhone 应用程序的下一个滴答声中,或者可能发生在控制台应用程序NSRunLoop的末尾。@autoreleasepool

于 2012-05-26T15:47:18.637 回答