@autoreleasepool {
MJPerson *person = [[[MJPerson alloc] init] autorelease];
}
转成C++代码
{
__AtAutoreleasePool __autoreleasepool;
MJPerson *person = ((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MJPerson"), sel_registerName("alloc")), sel_registerName("init")), sel_registerName("autorelease"));
}
__AtAutoreleasePool结构
struct __AtAutoreleasePool {
__AtAutoreleasePool() { // 构造函数,在创建结构体的时候调用
atautoreleasepoolobj = objc_autoreleasePoolPush();
}
~__AtAutoreleasePool() { // 析构函数,在结构体销毁的时候调用
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
void * atautoreleasepoolobj;
};
所以autoreleasepool底层就是
@autoreleasepool {
// 创建时调用push
// atautoreleasepoolobj = objc_autoreleasePoolPush();
MJPerson *person = [[[MJPerson alloc] init] autorelease];
// 销毁时调用pop
// objc_autoreleasePoolPop(atautoreleasepoolobj);
}
push 和 pop 分别调用的方法
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
所以调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的
每个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址
所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起
流程
调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址
对象调用autorelease,会将其地址放入当前的AutoreleasePoolPage中
调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY
id *next指向了下一个能存放autorelease对象地址的区域
嵌套的autoreleasepool释放
@autoreleasepool { // r1 = push()
MJPerson *p1 = [[[MJPerson alloc] init] autorelease];
MJPerson *p2 = [[[MJPerson alloc] init] autorelease];
@autoreleasepool { // r2 = push()
for (int i = 0; i < 600; i++) {
MJPerson *p3 = [[[MJPerson alloc] init] autorelease];
}
@autoreleasepool { // r3 = push()
MJPerson *p4 = [[[MJPerson alloc] init] autorelease];
} // pop(r3)
} // pop(r2)
} // pop(r1)
流程为执行到pop(r3)时先p4发送release 然后遇到对应的POOL_BOUNDARY结束,执行到pop(r2)时,p3发送release释放遇到对应的POOL_BOUNDARY结束,执行到pop(r1)时p2,p1调用release遇到POOL_BOUNDARY结束.
autorelease对象在什么时机会被调用release
- (void)viewDidLoad {
[super viewDidLoad];
// 这个Person什么时候调用release,是由RunLoop来控制的
// 它可能是在某次RunLoop循环中,RunLoop休眠之前调用了release
MJPerson *person = [[[MJPerson alloc] init] autorelease];
NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"%s", __func__);
}
iOS在主线程的Runloop中注册了2个Observer
第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
第2个Observer
监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()