在苹果对于 NSAutoreleasePool 的文档中表示:
每个线程(包括主线程),都维护了一个管理 NSAutoreleasePool 的栈。当创先新的 Pool 时,他们会被添加到栈顶。当 Pool 被销毁时,他们会被从栈中移除。
autorelease 的对象会被添加到当前线程的栈顶的 Pool 中。当 Pool 被销毁,其中的对象也会被释放。
当线程结束时,所有的 Pool 被销毁释放。
对 NSAutoreleasePool 类方法和 autorelease 方法打断点,查看其运行过程,可以看到调用了以下函数:
[NSAutoreleasePool showPools]
可以看到当前线程所有 pool 的情况:
在 objc4 中可以查看到 AutoreleasePoolPage:
AutoreleasePoolPage 以双向链表的形式组合而成(分别对应结构中的 parent 指针和 child 指针)。
thread 指针指向当前线程。
每个 AutoreleasePoolPage 对象会开辟4096字节内存(也就是虚拟内存一页的大小),除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址。
next 指针指向下一个 add 进来的 autorelease 的对象即将存放的位置。
一个 Page 的空间被占满时,会新建一个 AutoreleasePoolPage 对象,连接链表。
有时候我们除了 __weak
和 __strong
之外也会用到 __unsafe_unretained
这个修饰符,那么我们对 __unsafe_unretained
了解多少?
__unsafe_unretained
是不安全的所有权修饰符,尽管 ARC 的内存管理是编译器的工作,但附有 __unsafe_unretained
修饰符的变量不属于编译器的内存管理对象。赋值时即不获得强引用也不获得弱引用。
来运行一段代码:
运行结果:
对代码进行详细分析:
所以,最后的 NSLog 只是碰巧正常运行,如果错误访问,会造成 crash
在使用 __unsafe_unretained
修饰符时,赋值给附有 __strong
修饰符变量时,要确保对象确实存在