理解自动释放池

首先来段官方文档:

Important

If you use Automatic Reference Counting (ARC), you cannot use autorelease pools directly. Instead, you use @autoreleasepool blocks. For example, in place of:

Code Listing 1
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Code benefitting from a local autorelease pool.
[pool release];

you would write:

Code Listing 2
@autoreleasepool {
    // Code benefitting from a local autorelease pool.
}

@autoreleasepool blocks are more efficient than using an instance of NSAutoreleasePool directly; you can also use them even if you do not use ARC.


大家都知道,自动释放池是用来存放那些需要在稍后某个时刻释放的对象,清空(drain)自动释放池时,系统会向其中的对象发送release消息。

在使用的过程中,你有没有下面这些疑问:

问题1:

都知道程序入口main会自动创建一个自动释放池,如下:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
这个块的末尾就是应用程序的终止处,这个时候操作系统就会把程序所占有的全部内存释放掉,还要自动释放池做甚?


问题2:

那些程序中加入到1中池子里面的自动释放的对象难道也是这个时候才被销毁,那和内存泄漏有啥区别啊?


问题3

什么时候用池来优化效率


问题4:

自动释放池什么时候被释放


问题一一解答:

问题1:

如果不写这个块的话,那么由UIApplicationMain函数所自动释放的那些对象,就没有自动释放池可以容纳了,于是系统会发出警告信息,所以说,这个池可以理解成最外围捕捉全部自动释放对象所用的池。


问题2:

以下是苹果官方文档

The Application Kit creates an autorelease pool on the main thread at the beginning of every cycle of the event loop, and drains it at the end, thereby releasing any autoreleased objects generated while processing an event. If you use the Application Kit, you therefore typically don’t have to create your own pools. If your application creates a lot of temporary autoreleased objects within the event loop, however, it may be beneficial to create “local” autorelease pools to help to minimize the peak memory footprint.

这里的大概意思就是说,应用程序库会在主线程的每个事件循环周期的开始创建一个自动释放池,并在结束的时候清空它,从而在处理一个事件的时候释放掉所有之前生成的自动释放的对象;如果你使用应用程序库,你通常不需要自己来创建你自己的池。但是,如果你的应用在应用循环周期内创建很多临时的自动释放对象,创建“本地”自动释放池可能有利于帮助减少峰值内存占用。


举个栗子:

    for (int i = 0; i < 10000; i++) {
        NSMutableArray *mArray = [NSMutableArray array];
        [mArray addObject:@"temp"];
    }

分析:上面的例子中,创建了很多临时数组对象,可是每次循环完以后,它们都不会再使用了,但是它们依然处于存活状态,目前还在释放池中,等待系统稍后将其释放并回收。然而,自动释放池要等线程执行下一次事件循环时才会清空。这就意味着在执行for循环时,会持续有新对象创建出来,并加入自动释放池,所有这种对象都要等for循环执行完才会释放,这样一来,在执行for循环时,应用程序所占内存量就会持续上涨,而等到所有临时对象释放后,内存用量又会突然下降。

解决方法:如下,很明显,不用再分析了。

    for (int i = 0; i < 10000; i++) {
        @autoreleasepool{
            NSMutableArray *mArray = [NSMutableArray array];
            [mArray addObject:@"temp"];
        }
    }

这里还要注意的是Mac OS X和iOS应用程序分别运行于Cocoa和Cocoa Touch环境,系统会自动创建一些线程,比如说主线程或是“大中枢派发”(Grand Central Dispatch,GCD)机制中的线程,这些线程默认都有自动释放池,每次执行"事件循环"(event loop)时,就会将其清空。因此,不需要自己来创建自动释放池块。


问题3:

尽管自动释放池块的开销不太大,但是毕竟还是有的,所以尽量不要建立额外的自动释放池,优化之前可以先监控内存用量,看是否需要。


问题4:

以下是苹果官方文档

You create an NSAutoreleasePool object with the usual alloc and init messages and dispose of it with drain (or release—to understand the difference, see Garbage Collection). Sinceyou cannot retain an autorelease pool (or autorelease it—see retain and autorelease),draining a pool ultimately has the effect of deallocating it.You should always drain an autorelease pool in the same context (invocation of a method or function, or body of a loop) that it was created. See Using Autorelease Pool Blocks for more details.

Each thread (including the main thread) maintains its own stack of NSAutoreleasePoolobjects (see Threads). As new pools are created, they get added to the top of the stack. When pools are deallocated, they are removed from the stack. Autoreleased objects are placed into the top autorelease pool for the current thread. When a thread terminates,it automatically drains all of the autorelease pools associated with itself.

红线部分就是答案,清空池最终会导致销毁,当前线程终止的时候会自动清空相关联的所有的池。

这里的大概意思就是说,每个线程包括主线程都保持它自己的自动释放池的栈,当新的池被创建,它们被添加到栈的顶部,放池被销毁,它们会从栈移除,自动释放的对象被放在当前线程的最顶部的自动释放池中,当线程被终止,它会自动清空所有与自己关联的自动释放池。



猜你喜欢

转载自blog.csdn.net/junjun150013652/article/details/53083780