内存布局
- 栈(stack):方法调用,局部变量,是连续的,高地址向低地址扩展
- 堆(heap):通过alloc等分配的对象,是离散的,低地址向高地址扩展,需要手动管理
- 未初始化数据(bss):未初始化的全局变量等
- 已初始化数据(data):已初始化的全局变量等
- 代码段(text):程序代码
问题一 :Autoreleasepool是实现机制是什么?它是什么时候释放内部的对象的?它内部的数据结构是什么样的?当我提到哨兵对象时,会继续问哨兵对象的作用是什么,为什么要设计它?
编译器会将 @autoreleasepool {} 改写为:
void * ctx = objc_autoreleasePoolPush;
{}
objc_autoreleasePoolPop(ctx);
- objc_autoreleasePoolPush:
把当前next位置置为nil,即哨兵对象,然后next指针指向下一个可入栈位置,AutoreleasePool的多层嵌套,即每次objc_autoreleasePoolPush,实际上是不断地向栈中插入哨兵对象。 - objc_autoreleasePoolPop:
根据传入的哨兵对象找到对应位置。
给上次push操作之后添加的对象依次发送release消息。回退next指针到正确的位置。
Autoreleasepool的原理是一个双向列表,它会对加入其中的对象实现延迟释放。
当Autoreleasepool调用drain方法时会释放内部标记为autorelease的对象
Autoreleasepool数据结构
class AutoreleasePoolPage {
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
};
哨兵对象类似一个指针,指向自动释放池的栈顶位置,它的作用就是用于标记当前自动释放池需要释放内部对象时,释放到那个地方结束,每次入栈时它用于确定添加的位置,然后再次移动到栈顶。
问题二 :哪些对象会放入到Autoreleasepool中?
有两种情况生成的对象会加入到autoreleasepool中:
- 非alloc/new/copy/mutablecopy 开始的方式初始化时
- id的指针或对象的指针在没有显示指定时