Objective c 在main()中省略@autoreleasepool{}会有什么后果?
为什么Objective-C命令行和iOS程序的Xcode 4.x模板添加了Objective c 在main()中省略@autoreleasepool{}会有什么后果?,objective-c,macos,memory-management,clang,Objective C,Macos,Memory Management,Clang,为什么Objective-C命令行和iOS程序的Xcode 4.x模板添加了@autoreleasepool{}部件包装main()的代码?请注意,OSX应用程序模板不会发生这种情况 为什么OSX应用程序不这样做?为什么两者不使用相同的方法 最后,由于任何程序退出时都会释放所有内存,为什么所有这些都是实用的 或者换一种说法,对于命令行或iOS Objective-C程序,在main()中省略@autoreleasepool{…}的实际后果是什么 这两段代码可以编译,并且似乎可以等效地工作: 一
@autoreleasepool{}
部件包装main()
的代码?请注意,OSX应用程序模板不会发生这种情况
为什么OSX应用程序不这样做?为什么两者不使用相同的方法
最后,由于任何程序退出时都会释放所有内存,为什么所有这些都是实用的
或者换一种说法,对于命令行或iOS Objective-C程序,在
main()
中省略@autoreleasepool{…}
的实际后果是什么
这两段代码可以编译,并且似乎可以等效地工作:
一,
二,
注意,我只关心ARC上下文中的解释。ARC禁止显式使用
自动释放
在上面的代码示例中,您没有使用任何自动释放的对象
但是,如果你在做这样的事情:
NSString * somethingToSay = [NSString stringWithString:@"this is an autoreleased string, believe it or not"];
NSLog(@"%@", somethingToSay);
return 0;
“@autoreleasepool
”位实际上更有用
,他们说:
在自动释放池块的末尾,接收到
块内的自动释放消息发送一条释放消息
对象每次发送释放消息时都会收到一条释放消息
块内的自动释放消息
因此,当您有很多自动释放的对象时(您可以创建很多对象,这些对象最终成为NSArray、NSDictionary、NSString等),这些自动释放池有助于释放内存
应用程序模板在main.m中包含“
@autoreleasepool
”,因为在iPhone或iPad等设备上,内存使用至关重要,我们希望确保在应用程序退出“UIApplicationMain
”时,所有内存都得到正确释放(不太可能,因为大多数人都会让iPhone应用程序一直运行到重新启动,但这种情况可能会发生)。autorelease
如果堆栈上没有自动释放池,则无法工作
在objective-c中没有必要使用自动释放对象(正如您在示例中所做的那样),因此理论上可以省略它,但是大多数Apple框架确实大量使用自动释放对象
通常,每个线程都应该至少有一个自动释放池,否则使用任何Obj-C代码都是非常不安全的。在main
的开头设置自动释放池是一个非常好的做法
编辑:
在ARC中,虽然禁止显式的autorelease
,但是仍然存在autorelease
调用(由编译器添加)。这意味着需要一个autorelease池
这与释放内存无关。自动释放池的存在是必要的,即使它从未耗尽
我猜OSX没有将自动释放池添加到模板中,因为程序员也可以使用垃圾收集器(尽管现在不推荐使用)
编辑2:
刚刚创建了一个OSX项目,并且有@autoreleasepool
。事实上,没有它的唯一模板是一个“核心基础”项目,它不是真正的Obj-C,它是纯C
编辑3:(经过一些思考和谷歌搜索)
随着ARC的引入,自动释放池被重写。以前它们是一种框架特性,现在它们是一种语言(Obj-C)功能。它们的实现方式不同。现在似乎每个新线程都有一个隐式自动释放池。使用@autoreleasepool
实际上不再在某个线程堆栈上创建新的自动释放池,它只是在隐式自动释放池中添加一个标记(这样您就可以在标记后耗尽所有自动释放的内容)。这意味着在省略@autoreleasepool
时,无法创建触发警告或错误的示例
但是,这被认为是一个实现细节,因此在将来(或使用其他编译器时!)可以很容易地对其进行更改。这就是为什么最好还是为每个新线程设置一个
@autoreleasepool
(例如,在-[NSThread detachWithSelector:…]
文档中提到).您需要它,因为文档上说您需要它。这应该足够了,相信文档:
通常,您不需要创建自己的自动释放池块,但在某些情况下,您必须这样做,或者这样做是有益的
Cocoa总是希望代码在自动释放池中执行
块,否则自动释放的对象不会被释放,并且
应用程序内存泄漏。(如果您在外部发送自动释放消息。)
对于自动释放池块,Cocoa会记录适当的错误消息。)
…但是,在三种情况下,您可能会使用自己的自动释放池块:
- 如果您正在编写一个不基于UI框架的程序,例如命令行工具
如果您遵循推荐的最佳实践,那么您的代码在20年后仍然可以正常运行,但如果您不这样做,从下一次x.x.x操作系统更新开始,每50次执行中可能会随机崩溃一次。苹果文档中的这句话可能会有所帮助: 如果分离的线程不进行Cocoa调用,则不需要使用自动释放池块 这可以推断为
int main(int argc, const char * argv[])
{
NSArray *array = @[@"Hello, world!"];
NSLog(@"%@", array[0]);
}
NSString * somethingToSay = [NSString stringWithString:@"this is an autoreleased string, believe it or not"];
NSLog(@"%@", somethingToSay);
return 0;