Objective C - autoreleasepool和ARC泄漏内存

时间:2013-05-28 08:57:59

标签: objective-c automatic-ref-counting autorelease

根据我的理解,如果ARC已启用,则@autoreleasepool{}内的对象应在不再使用时释放。

然而,代码

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        for (int i = 0; i < 1000000000; i++) {
            NSString *string = @"ab c";
            NSArray *array = [string componentsSeparatedByString:string];
        }
    }
    return 0;
}

泄漏记忆。

仪器显示泄漏的对象是__NSArrayM创建的 - [NSString componentsSeparatedByString:]

所以,问题是:为什么__NSArrayM对象在它们被创建的同一循环迭代中没有被销毁?

任何人都可以帮我解决这个问题

更新:感谢您的回答,似乎我错误地使用了“内存泄漏”一词,并误解了@autoreleasepool{}的工作原理。要解决此问题,我应该将@autoreleasepool{}放在for循环中。

3 个答案:

答案 0 :(得分:3)

你的理解是错误的

  1. 这与ARC没有任何关系
  2. 这不是垃圾收集,因此对象在停止使用时不会被释放
  3. 自动释放池在耗尽([NSAutoreleasePool drain])或销毁时释放对象。你没有明确地排空游泳池,所以它只会在return之前排空一次。

答案 1 :(得分:3)

  

据我了解,如果启用了ARC,@ autoreleasepool {}内的对象应该在不再使用时释放。

好的,退后一步,实际上想一想。对于每次内存泄漏,ARC都不是一个神奇的解决方案,它仍然是手动保留释放,只是编译器插入手动保留释放。在给出“内存泄漏”的例子时,@autoreleasepool {}并没有避免谨慎的需要,它也没有赋予你分配10亿个对象并将其称为框架bug的权利。事实证明,你所做的可能是重载了它给你的自动释放池,你要么没有等待足够长的时间让循环正常终止,要么你被操作系统杀死(我敢打赌)后者多于前者)。自己运行之后,我可以确认给定的自动释放池确实耗尽了这个分配的RAM的Gigs,它只需要很长时间。

如果你移除了循环,甚至缩短了它的持续时间(100,甚至1000就足够了),你可以看到绝对没有物体泄漏,并且一切都正确地影响了恐龙:

enter image description here

答案 2 :(得分:3)

要了解autorelease的工作原理,请将以下代码与原始代码进行比较:

for (int i = 0; i < 1000000000; i++)
{
    @autoreleasepool
    {
        NSString* string = @"ab c";
        NSArray* array = [string componentsSeparatedByString:string];
    }
}

自动释放的对象在超出范围时会被标记为释放,但在自动释放部分结束之前(自动释放池耗尽)才会实际释放。因此,上面的代码每次都会在循环中释放标记的对象,而原始代码只会在循环结束时释放它们。

自动释放池可以嵌套,在自动释放对象时使用最接近的池。这允许您从[NSString stringWithFormat:@"%d", i];等函数返回对象 - 返回的字符串的保留计数为1但标记为自动释放 - 您可以暂时使用它,但如果您需要保留它以供以后使用,则需要保留它(当你将它分配给强引用时会发生)。因此,当你保留它时,保留计数变为2,然后当它自动释放时,保留计数变为1并且一切都很好。如果你从未保留它,那么当自动释放时,保留计数变为0并且对象被解除分配。