1

据我了解,如果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;
}

泄漏内存。

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

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

谁能帮我解决这个问题

更新:感谢您的回答,看来我错误地使用了“内存泄漏”一词,并且误解了它的@autoreleasepool{}工作原理。为了解决这个问题,我应该放在@autoreleasepool{}for 循环中。

4

3 回答 3

3

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

好的,退后一步,真正考虑一下。ARC 并不是所有内存泄漏的神奇包罗万象,它仍然是手动保留释放,只是编译器插入手动保留释放。 @autoreleasepool {}在给出“内存泄漏”的例子时并没有排除谨慎的必要性,也没有赋予您分配 10 亿个对象的权利并将其称为框架错误。事实证明,你所做的可能是它交给你的自动释放池超载了,你要么没有等待足够长的时间让循环正确终止,要么你被操作系统杀死(我敢打赌后者多于前者)。我自己运行了这个,我可以确认给定的自动释放池确实耗尽了它分配的 Gigs 内存,它只需要相当长的时间。

如果您删除循环,甚至缩短其持续时间(100 甚至 1000 应该足够了),您可以看到绝对没有物体泄漏,并且一切都按照恐龙的方式进行:

在此处输入图像描述

于 2013-05-28T09:40:28.247 回答
3

要了解自动释放的工作原理,请将以下代码与您的原始代码进行比较:

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 并且对象被释放。

于 2013-05-28T10:33:20.437 回答
3

你的理解是错误的

  1. 这与ARC没有任何关系
  2. 这不是垃圾回收,所以对象在停止使用时不会被释放
  3. 自动释放池在耗尽 ( [NSAutoreleasePool drain]) 或销毁时释放对象。您没有明确地排空池,因此它只会在之前排空一次return
于 2013-05-28T09:38:15.907 回答