使用[NSDate date]时为什么ARC不释放内存,但使用[[NSDate alloc] init]工作正常?

时间:2013-06-20 08:26:40

标签: objective-c automatic-ref-counting

我已经编写了一些似乎工作正常的Objective-C应用程序,除了不断增长的内存占用。我在最新版本的Xcode 4.6.2下使用ARC。我的系统是10.7.5。

我对Objective-C非常陌生,需要一些帮助来弄清楚我的记忆是怎么回事。我已经将问题缩小到解释为什么以下基本代码行为与它一样。

此代码添加在Xcode提供的基于香草Cocoa的应用程序模板中(启用了ARC)。

案例A

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
    NSDate* d;
    for(int i=0; i<1000000; i++){
        d = [[NSDate alloc] init];
    }
}

一切都按预期进行,ARC即时回收内存。即,内存使用历史非常平坦。当for循环结束时,应用程序需要大约25MB内存。

案例B

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
    NSDate* d;
    for(int i=0; i<1000000; i++){
        d = [NSDate date];
    }
}

这里的事情对我来说真的很神秘。当刚刚运行应用程序时,(实际)内存使用量持续增加到大约53MB,然后永远保持在那里。

但是,在运行分配探查器工具时,我可以看到在for循环结束时,所有对象都被释放,非常像您对自动释放池所期望的那样。此外,用@autoreleasepool {}封闭for循环的主体使得大小写B的行为类似于大小写A(如预期的那样)。

所以,有三个问题:

  1. 在ARC下,使用&#34;自动释放&#34;有什么区别? [NSDate date]和alloc init对象? (我认为这里的其他问题几乎没有。)
  2. 为什么ARC在运行代码时似乎没有启动?
  3. 为什么配置文件应用程序和实际应用程序的内存行为存在差异?

2 个答案:

答案 0 :(得分:4)

最终会释放自动释放对象,而在alloc / init情况下,它们会在不再使用时立即释放。

此行为会导致您的对象在整个循环中保留在内存中,以防它们在以后发布时自动释放,而如果您alloc / init,则release方法在 循环体中发送。

通过将其包裹在@autoreleasepool中,您可以轻松地使身体循环具有内存效率:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
    @autoreleasepool {
        NSDate* d;
        for(int i=0; i<1000000; i++){
            d = [NSDate date];
        }
    }
}

这将给ARC一个提示,表示您希望在每次循环迭代时创建和释放自动释放池。

在特定情况下,最简单的选择可能是使用alloc / init方法,以便编译器自动执行正确的操作,但是如果你有一个包含许多工厂的循环体返回自动释放实例的方法,@autoreleasepool块可能是一个很好的方法。

作为最后的评论,@autoreleasepool不是ARC专有的。它曾经存在于LLVM 3.0之后,并且具有足够的现代目标(即iOS5和OSX 10.7),它已经比老式的NSAutoreleasePool快得多。

答案 1 :(得分:2)

[NSDate date]正在创建一个自动释放的对象,该对象将在您的程序下次进入事件循环时释放。

另一种情况是由ARC在循环中释放的。

如果你真的想做这样的事情,你可以创建自己的自动释放池并定期排干它。请参阅示例Objective-C: Why is autorelease (@autoreleasepool) still needed with ARC?