iOS autoreleasepool 原理
NSMutableArray *arr = [NSMutableArray array];
NSLog(@"%@",arr);
arr 是再什么时机释放?
@AutoreleasePool{代码} 会被编译器改写为
void *ctx = objc_autoreleasePoolPush();
{}代码
objc_audoreleasePoolPop(ctx);
源码
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
一次 pop 相当于一次批量的pop操作
AutoreleasePool 实现原理
是以栈为节点通过双向链表的形式组合而成的,是和线程一一对应的
autoreleasePoolPage 数据结构
可在源码中查看
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
next 其实就是指向栈中下一个可填充的位置,parent 和 child 也就是双向链表的父指针和子指针,
栈顶 --- 低地址
next
id obj
id obj --- 栈底
AutoreleasePoolPage --- 高地址,自身占用内存
所以发生push,会把当前哨兵next位置指向nil,指向下一个位置,其实就是在栈中插入对象
[obj autorelease]过程
首先会判断是否到达了栈顶,没有的话就添加到栈中,增加一个栈节点到链表上面
pop 过程
1.根据传入的哨兵对象找到对应的位置
2.给上次push操作之后添加的对象一次发送release消息
3.会退到next指针的位置
所以上面的题,是再档次runloop将要结束的时候调用 autoreleasePoolPage::pop(),然后发送release消息,也就是pod操作,从栈中移除
AutoreleasePool 为何可以嵌套使用
多层嵌套就是多次插入哨兵对象,每次创建一个AutoreleasePool,@AutoreleasePool,其实系统就是为我们创建了一个哨兵对象,其实就是创建page,若果当前page没有满,其实就是创建一个哨兵,所以可以嵌套使用
一般什么时候用
比如for循环alloc图片等内存消耗比较大的数据,需要插入,防止当时内存消耗过大