(一)自动释放池的原理,
自动释放池是由多个autorelease page组成的双向链表,其中主要通过push及pop操作来管理:
push
自动释放池会先调用 objc_autoreleasePoolPush 函数,这函数首先在当前 next 指向的位置存放一个 POOL_BOUNDARY,然后当向一个对象发送 autorelease 消息时,会在哨兵对象后面插入指向该对象的指针,之后把 next 指向刚插入的位置的下一个内存地址,
当这一页 page 快满时(即 next 即将指向栈顶——end() 位置),说明这一页 page 快满了。这时如果再加入一个对象,会先建立下一页 page,双向链表建立完成后,新的 page 的 next 指向该页的栈底——begin() 位置,之后继续向栈顶添加新的指针。
pop
调用完前面说的objc_autoreleasePoolPush后,会返回一个POOL_BOUNDARY的地址,当对象要释放时,会调用objc_autoreleasePoolPop函数,将该POOL_BOUNDARY作为其入参,然后会执行如下操作:
根据传入的POOL_BOUNDARY(push后得到的那个)找到其所在的page;
从 hotPage 的 next 指针开始往前查找,向找到的每个指针调用 memset 方法以擦除指针所占内存,再调用 objc_release 方法释放该指针指向的对象,直到前一步所找到的 page 的 POOL_BOUNDARY 为止(可往前跨越多个 page),并且在释放前,next 指针也会往回指向正确的位置。
当有嵌套的 autoreleasepool 时,会清除一层后再清除另一层,因为 pop 是会释放到上次 push 的位置为止,就像剥洋葱一样,每次一层,互不影响。
二 、autorelease 对象会在什么时候释放?
分两种情况:
使用@autoreleasepool,会在大括号结束时释放
不使用 @autoreleasepool,这个会由系统自动释放,释放时机是在当前 runloop 结束时释放,因为系统会自动为每个 runloop 执行自动释放池的 push 和 pop 操作
关于内存管理的方法,目前来说,有三种:
C/C++的完全由程序员管理(paring new/malloc & delete/free);
Garbage Collection;
Reference Counting;
第一种比较原始;Cocoa Touch的Reference Counting对比Garbage Collection,有一个致命的弱点:无法释放循环引用的对象,所以要注意不要造成循环引用。
三、什么时候应该使用@autoreleasepool
你的程序不是基于 UI 框架的,如命令行工具
你编写的循环创建了大量的临时对象
如果你创建了一个辅助线程
网友评论