NSAutoReleasePool的疑问

来源:互联网 发布:手机淘宝6.6.0旧版本 编辑:程序博客网 时间:2024/06/11 14:07

autorelease的用法我了解,但是我一直有一个疑问:

 

比如说项目中我没有加其他的 NSAutoreleasePool ,也就是说项目中只有 主线程中的那个 NSAutoreleasePool.

我现在有(就拿NSString举例了)

 

- (IBAction)clickBtn:(id)sender

{

     NSString *string = [[NSString alloc] initWithString:@"1234567890"];

     [string autorelease];

}

 

我一直不明白的是,这个string什么时候被释放呢?

刚开始看obj-c的介绍书籍时,书上说: 每一个autorelase会将该变量注册到一个自动线程池,当线程池销毁时,会给该对象发一个relase消息,并将其销毁."

对于这个说法我很是疑惑,要真是这样,比如说我只有一个主线程中的 NSAutoreleasePool,我程序中那些autorelease的对象就只能等到主线程中的NSAutoreleasePool销毁时被销毁. 那也就是说,要等到程序退出了,这些对象才会被销毁 ?

很显然这个说法是有问题的.

 

这两天空闲的时间比较多,,终于把这个问题给弄明白了.

首先,关于autorelease,我找到了比较权威的说法:

 

---------------

Objects set to auto-release mean that they do not need to be explicitly released because they will be released when an auto-release pool is popped. The iPhone has an auto-release pool that runs on the main thread which usually releases objects at the end of an event loop. When you create your own threads, you must create your own auto-release pool.

---------------

from : http://www.codeproject.com/KB/iPhone/avoidiphoneleaks.aspx?display=Mobile

(在Eric Sadun的<< the iphone developer's cookbook>> 2rd 也有这样的介绍)

 

也就是说,一个autorelease的对象在事件结束后会被主线程的自动释放池释放掉.

比如上面 clickBtn:中的string,它会在这个方法结束后被立即释放.

 

至此,,这个问题就算是回答完毕了,最后补充三点:

1.程序中所有的NSAutoreleasePool对象都会被加到一个"栈"中,当你将一个对象定义为autorelease时,"栈"中最上面的NSAutoreleasePool对象负责管理的该对象的销毁.

2.碰到一些不明白的问题,很简单写个小程序,不费什么功夫.

3.刚开始学习一个新的技术,不能只看一本书,书毕竟是人写的,难免有疏漏或误导之处.


一般来说在应用的main thread中, 已经存在了一个autorelease pool. 有两种情况需要开发者自己新建autorelease pool:

  1. 在main thread中, 在某个方法中出现大量的autoreleased objects, 为了避免memory footprint的增大, 可以手动创建一些autorelease pool用来drain objects.
  2. 创建新的thread, 并在其中访问了Cocoa, 需要在访问的前创建autorelease pool, 访问结束后drain.

有时候我们为了程序的性能考虑,需要自己在适当的地方加上autorelease pool,以便及时释放掉内存.比如下面这种情况

view source
1for (int i = 0; i < numberOfImages; ++i) {
2    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3    //Loading images, etc.
4    //Too many autoreleased objects exist.
5    [pool drain];
6    //All the autoreleased objects are released by [pool drain].
7}

 

如果不及时释放内存,则多次循环后图片和相关资源占用着内存,瞬间使得内存占用飙升。


最后一点, 在每个thread中都会维持一个stack, 其中放置着所有在这个thread中创建但未销毁的pool, 每当一个新的pool创建后, 它就位于stack的最顶端,  相应autoreleased object就会放入其中. 当pool drain的时候, 它就会从stack的顶端移除, 并且release掉其包含的objects.


应用程序框架会在每次主线程驱动事件循环开始时创建一个自动释放池。当这个事件循环结束时,会释放掉这个事件循环过程中产生的自动释放对象。所以我们基本上不用自己去创建自动释放池。如果你在程序中的某段代码快内创建了大量的自动释放的临时对象,那么你应该在代码快的开始创建自己的自动释放池。

什么是事件循环呢?这里引用Apple文档里面的一句话:

An event loop is simply a run loop: an event-processing loop for scheduling work and coordinating the receipt of events from various input sources attached to the run loop.

可以是NSTimer的一次回调过程,或者某个iphone上的触摸事件,异步http连接下当接受完数据时,甚至是程序代理类控制的各个过程,比如加载完成时,即将结束时的函数调用。

每个线程(包含主线程)都有一个管理NSAutoreleasePool实例的栈。当自动释放池创建后就会被压入栈中,当释放时就会从栈顶弹出。当线程终止时,所有在该线程栈中的NSAutoreleasePool实例都会被释放。



深圳的朋友加群109488600 ,大家一起交流IOS