接着上一篇的笔记,上一篇记录了 retain,release 的实现,今天的笔记主要是从
autorelease
出发。
**autorelease的理解 **
定义
autorelease 顾名思义及时自动释放的意思。它有点类似 C 语言中自动变量的特性。程序执行时,若自动变量超出其作用域,该自动变量将被自动废弃。
接着我们看看autorelease具体的使用方法:
- 1、生成并持有 NSAutoreleasePool 对象
- 2、调用已分配对象的 autorelease 实例方法
- 3、废弃 NSAutoreleasePool 对象
// 用源代码表示如下
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain]; // 等同于 obj release
因此我们也可以这样理解,Autorelease Pool使用场景就是需要延迟释放某些对象的情况时,可以把他们先放到对应的Autorelease Pool中,等Autorelease Pool生命周期结束时再一起释放。
苹果中很多类方法用于返回 autorelease 的对象,例如像下面这两者是相等的:
NSMutableArray *testArray = [NSMutableArray arrayWithCapacity:4];
NSMutableArray *testArray = [[NSMutableArray alloc] initWithCapacity:4];
以及
// 等同于一个局部对象,封装了autorelease方法
NSString *testString = [NSString stringWithFormat:@"testString"];
什么时候使用
@autoreleasepool { };
根据Apple的文档,使用场景如下:
写基于命令行的的程序时,就是没有UI框架,如AppKit等Cocoa框架时。
写循环,循环里面包含了大量临时创建的对象。
创建了新的线程。(非Cocoa程序创建线程时才需要)
长时间在后台运行的任务。
利用@autoreleasepool优化循环的内存占用,可能是我们会用到的一点。如下面的循环,次数非常多,而且循环体里面的对象都是临时创建使用的,就可以用@autoreleasepool包起来,让每次循环结束时,可以及时的释放临时对象的内存。
for (int i = 0; i < 10000; i++) {
@autoreleasepool {
// 创建对象 TODO:
NSObject *obj = [[NSObject alloc]init];
};
}
源码如何实现的?
通过 objc4 库 runtime/objc-arr.mm 来确认苹果中的 autorelease 的实现。
class AutoreleasePoolPage
{
static inline void *push()
{
// 相当于生成或持有 NSAutoreleleasePool 类对象
}
static inline void *pop (void *token)
{
// 相当于废弃 NSAutoreleasePool 类对象
releaseAll();
}
static inline id autorelease(id obj)
{
// 相当于 NSAutoreleasePool 类的 addObject 类对象
AutoreleasePoolPage *autoreleasePoolPage // 取到正在使用的AutoreleasePoolPage的实例
autoreleasePoolPage->add (obj);
}
id *add (id obj)
{
// 将对象追加到内部数组中
}
void releaseAll()
{
// 调用内部数组中对象的 release 的实例方法
}
};
void *obj_autorelreasePoolPush (void)
{
return AutoreleasrPoolPage::push();
}
void objc_autoreleasePoolPop (void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
id objc_autorelease (id obj)
{
return AutoreleasePoolPage::autorelease(obj);
}
再直接点用,例如 ARC 中我们使用@autoreleasepool{}
来使用一个AutoreleasePool的是时候,编译器就将其改写成下面的样子:
void *context = objc_autoreleasePoolPush();
// {}中的代码,所有接收到 autorelease 消息的对象会被添加到这个 autoreleasepool 中
objc_autoreleasePoolPop(context);
所以可以这样理解,它实际上执行的也就是 Push 和 Pop 的操作,Push 生成,Pop 废弃,遵循"先进后出"的原则。单个 autoreleasepool 的运行过程可以简单地说就是 obj_autorelreasePoolPush
、[对象 autorelease]
和 objc_autoreleasePoolPop
这三个过程。
备注:参考下面这两篇博文,都是非常赞的
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
http://blog.leichunfeng.com/blog/2015/05/31/objective-c-autorelease-pool-implementation-principle/