iOS 自动释放池原理

1. OC示例

- (void)viewDidLoad{
	[super viewDidLoad];
	NSMutableArray * array=[NSMutableArray array];
	NSLog(@"%@",array);
}

编译器的会将@autoreleasePool改写成

void * ctx=objc_autoreleasePoolPush();
{}中的代码
objc_autorelaesePoolPop(ctx);

一次objc_autoreleasePoolPush操作相当于一次批量次的AutoReleasePoolPagePop操作。会把{}中的对象全部压入栈结构。

2 .自动释放池的数据结构是怎样工作的?

以栈为结点的双向链表

1)结点结构

iOS 自动释放池原理_第1张图片
next指针:栈顶指针,也是使用哨兵的插入位置,每一次自动释放池进行嵌套自动释放池的时候都会插入一个next哨兵。当被嵌套的自动释放池被释放的时候,从栈顶到上次哨兵插入的位置之间的批量对象会被依次次发送release方法。

iOS 自动释放池原理_第2张图片

parent和child指针:即前后AutoreleasePoolPage结点。

thread:当前线程,每个线程都有自己的自动释放池子,在哪个线程创建的自动释放池就必须在哪个线程去释放。

2)autorelasePoolPage:Push

iOS 自动释放池原理_第3张图片
当调用autoreleasePoolPagePop的时候,首先会判断栈顶指针是否已经到达当前栈最大容量,如果没有,对象直接入栈,如果有创建一个新的栈结点添加到链表中,然后在将对象入栈于新栈中。

3)autorelasePoolPage:pop

根据传入的哨兵对象找到对应位置,然后给上次哨兵位置之后添加的对象依次发送release消息,回退next到正确位置。

3 自动释放池的释放时机和使用场景

1)释放时机

从程序启动到加载完成是一个完整的运行循环,然后会停下来,等待用户交互,用户的每一次交互都会启动一次运行循环,来处理用户所有的点击事件、触摸事件。

释放时机:当runloop即将进行休眠状态时会销毁旧的释放池,并创建一个新的释放池

其实本质上说是在本次runloop迭代结束时清理掉被本次迭代期间被放到autorelease pool中的对象的。至于何时runloop结束并没有固定的duration!

2)使用场景

1 使用容器的block版本的枚举器时,内部会自动添加一个AutoreleasePool:

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// 这里被一个局部@autoreleasepool包围着
}];

2写给予命令行的程序时,就是没有UI框架;
3写循环,循环里边包含了大量临时创建的对象;
4创建了新的线程;
5长时间在后台运行的任务;
6合理运用自动释放池,可以降低程序的内存峰值,异步的方式将文件保存在磁盘(SDWebimage里边异步保存图片到磁盘,类似的占用内存的操作);

7

你可能感兴趣的:(ios,ios,objective-c,xcode)