苹果官方文档NSAutoreleasePool
NSAutoreleasePool这个类被用于支持Cocoa的引用计数内存管理机制. 当一个autorelease pool被drain(释放)的时候会对池子里的对象发送一条release的消息.
如果你的工程是ARC的, 那么你不能直接使用autorelease pool, 作为代替, 你应该使用@autoreleasepool {} 这个block. 官方代码如下 :
@autoreleasepool
Ps : 官方文档说明, 使用@autoreleasepool这个block比NSAutoreleasePool更高效!并且在MRC环境下同样适用
在引用计数的环境下(跟垃圾收集机制不同), 一个对象入池(NSAutoreleasePool对象)前均会收到一条autorelease的消息, 当池子被销毁的时候会发送一条release的消息给这些对象. 因此, 发送autorelease消息来代替发送release消息可以延长池中对象的生命周期, 直到池子被销毁. (这种情况下对象的生命周期有可能更长因为有可能有别的对象引用着这个池中的对象). 另外值得注意的是, 一个对象可以反复加入同一个池子中, 只是它每次入池之前都会先收到release消息.
在引用计数的环境下, Cocoa希望总是至少有一个可用的autorelease pool在程序中, 否则, 收到过autorelease的对象将不会对应地收到release的消息而导致内存泄漏. 在这种情况下, 你的程序一般会打印一些适当的警告信息.
Application Kit在开始每一个事件循环之前都会在主线程创建一个autorelease pool, 并且在事件循环结束的时候销毁它. 所以, 当处理完一个时间之后就会释放掉生成的autorelease对象. 如果你使用Application Kit的话, 一般来说你不需要手动创建autorelease pool. 但是如果你的应用在一个事件循环里面创建了大量的autorelease对象的话, 这时如果你能主动地创建一些局部的autorelease pools, 对减少内存占用的峰值具有一定的帮助.
用alloc-init方法创建一个NSAutoreleasePool对象和drain方法来处理它. 因为你不能retain一个autorelease pool, 所以drain方法相当于释放它的内存. 你应该在同一个环境, 上下文(调用创建这个池的同一个方法, 函数或者循环体)drain一个autorelease pool.
每一个线程(包括主线程)都维护着它自己的NSAutoreleasePool对象的栈. 当一个新的池子被创建的时候, 它被压到栈顶上. 当池子被释放内存时, 它们就会被移除出栈. autorelease对象被放在当前线程的栈顶池子中. 当一个线程终止的时候, 它会自动地drain掉所有跟它有关联的池子.
Threads
如果你正在Application Kit的主线程外边making Cocoa call, 例如, 如果你创建了一个Foundation-only 的应用或者你分离了一个线程, 你需要自己创建你自己的autorelease pool.
如果你的应用或者线程是长期存在的并且有可能生成很多autorelease对象, 你应该定期地drain和创建autorelease pools(就像Application Kit在主线程做的那样); 否则, autorelease对象会在内存中堆积造成内存占用攀登. 当然, 如果你分离的线程并没有make Cocoa call, 你就不需要去创建一个autorelease pool.
NOTE
如果你用POSIX thread APIs创建第二个线程来代替NSThread对象的话, 你不能使用Cocoa, 包括NSAutoreleasePool, 除非Cocoa处于多线程模式. Cocoa只有在它分离第一个NSThread对象之后才会进入多线程模式.要想在第二个POSIX线程中使用Cocoa, 你的应用必须至少分离了一个可以马上退出的NSThread对象. 你可以利用NSThread的类方法isMultiThreaded来测试Cocoa是否处于多线程模式.
Garbage Collection
在垃圾收集的环境下, autorelease pool没有存在的必要. 你可能想写一个同时可以工作在垃圾收集和引用计数两个环境下的框架. 这种情况下, 你可以使用autorelease pools去暗示收集器, 此次收集是否恰当. 在垃圾收集的环境下, 给pool发送drain信息, 如果有必要的话就会触发垃圾收集池进行垃圾收集. 然而, 给pool发送release等于什么也不做. 在引用计数的环境下, drain相当于release. 综上, 一般都会发送drain消息而不是release.
Managing a Pool
release
drain
autorelease
retain
release
释放并且从栈中弹出该消息的接收者
- (void)release
说明 :
在引用计数的环境下, 因为autorelease pool不能retain, 这个方法导致pool会被释放内存. 当一个autorelease pool被释放内存的时候, 他就会发送一条release给所有池中的autorelease对象. 如果一个对象被反复添加到相同的池中数次, 那么当池被释放的时候那么它每次添加到池中时都会收到一条release消息.
但是在垃圾收集的环境下, 这个方法不做任何事.
特殊情况
你应该用drain而不是release
drain
在引用计数的环境下, 释放并从栈中弹出这条消息的接收者;
在垃圾收集的环境下, 如果上次分配的内存集合已经大于当前的阈值, 就触发垃圾收集.
- (void)drain
说明 :
在引用计数的环境下, 这个方法等同于release. 因为autorelease pool不能retain, 所以这条消息会导致pool被释放内存. 当一个autorelease pool被释放内存的时候, 他就会发送一条release给所有池中的autorelease对象. 如果一个对象被反复添加到相同的池中数次, 那么当池被释放的时候那么它每次添加到池中时都会收到一条release消息.
特殊情况
在垃圾收集的环境下, release消息是一个空方法, 所以不管你的代码运行在什么环境下, 使用drain都是最佳方法, 除非你不想暗示收集器做事(在垃圾收集环境下).
有效性 :
OS X v10.4及之后有效
autorelease
增加一个例外
- (id)autorelease
返回值
自身
说明 :
在引用计数的环境下, 这个方法增加一个例外.
retain
同autorelease
Adding an Object to a Pool
+ addObject :
在当前线程下往有效的autorelease pool里添加一个给定的对象
+(void)addObject : (id)object
说明 :
相同的对象有可能会被重复加进有效的池子里, 当池子被释放内存时, 它每次被加进池子时都会收到release消息.
一般你不能显式地调用这个方法, 你应该调用对象的autorelease方法
有效性 :
OS X v10.0及以后有效
- addObject :
同上, 这是对象方法
Debugging
+ showPools
显示当前线程下autorelease pool栈的状态
+(void)showPools // objc
class func showPools() // swift