iOS笔记 - 内存管理:自动释放池的底层实现
作者:互联网
Autorelease底层实现
1 - 在了解 Autorelease之前,我们首先要了解自动释放池 __AtAutoreleasePool
① 在 main函数中创建 MJPerson对象
② 我们转换成 C++代码,如下
我们就看到了 __AtAutoreleasePool。把 C++代码按照 OC格式书写
原来 __AtAutoreleasePool是一个结构体。注:C++中的结构体类似 OC中的类
当代码执行到第 36行声明局部变量 __autoreleasepool时,就会自动调用结构体 __AtAutoreleasePool里面的 objc_autoreleasePoolPush()函数
当代码执行到第 38 行作用域 } 的结束,则自动调用 __AtAutoreleasePool里面的 objc_autoreleasePoolPop()函数
③ 到这里我们就知道了入池、出池的动作实际上是分别调用了 objc_autoreleasePoolPush和 objc_autoreleasePoolPop函数
2 - objc_autoreleasePoolPush | objc_autoreleasePoolPop
① push()函数。如果没有 pool page,就新建一个并把 POOL_BOUNDARY添加到 pool page中;如果存在 pool page则调用 autoreleaseFast函数(该函数会判断是否翻页),同样把 POOL_BOUNDARY添加到 pool page中
我们可以顺便扫两眼 autoreleaseFast函数
② pop函数,token就是 POOL_BOUNDARY
通过以上代码我们知道,pop函数其实就是把 token传递给 stop,然后调用 releaseUtil(stop)函数遍历检测,直到释放对象
③ 我们回过头来看一看 OC中的 Aurorelease方法:首先走的是 rootAutorelease、其次 rootAutorelease2、再次 aurorelease,最终还是调用了
autoreleaseFast函数
3 - AutoreleasePoolPage:上面说了那么多,关键点还是看 AutoreleasePoolPage
① 打开 AutoreleasePoolPage,这里只保留了用到的七个成员变量
② 如下有一个 pool page
begin() 其实就是起始地址 0x1000 + 这个 page的大小。每个 AutoreleasePoolPage对象占 4096字节,用来存储它的成员变量,剩下的存放 autorelease对象地址
如果存放的 autorelease对象超出 4096个字节系统就会启用一个新的 AutoreleasePoolPage直至把对象全部存进,所有 AutoreleasePoolPage对象是通过双向链表形式链接在一起的,这就是成员变量 parent/child的作用
注:id *next指向的是下池中的下一个对象,而不是下一个 pool page
我们可以大致看一下 begin/end相关函数
结语
1 - 自动释放池的底层工作原理
① 首先调用 push函数会将一个 POOL_BOUNDARY(默认 nil)入栈,并返回其内存地址 0x1038,注:是从 begin处开始,而不是从 0x1000处开始
② 最后调用 pop函数时会传入 POOL_BOUNDARY的内存地址,然后从最后一个入栈的对象开始发送 release消息,直到遇到这个 POOL_BOUNDARY
注:其实关键点就是对 AutoreleasePoolPage的使用
2 - 可以调用私有函数 void _objc_autoreleasePoolPrint(void)查看自动释放池的信息
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 // 系统私有函数,引用后 Runtime会自动查询调用 4 extern void _objc_autoreleasePoolPrint(void); 5 int main(int argc, const char * argv[]) { 6 7 @autoreleasepool { // POOL_BOUNDARY 8 Person *p1 = [[[Person alloc] init] autorelease]; // p1 9 10 @autoreleasepool { // 又进来一个 POOL_BOUNDARY 11 Person *p2 = [[[Person alloc] init] autorelease]; // p2 12 13 @autoreleasepool { // 又进来一个 POOL_BOUNDARY 14 Person *p3 = [[[Person alloc] init] autorelease]; // p3 15 Person *p4 = [[[Person alloc] init] autorelease]; // p4 16 17 // 应该是: 7 releases pending. 18 _objc_autoreleasePoolPrint(); 19 // page 中的有 3个 POOL_BOUNDARY+ 4个 Person对象 20 NSLog(@"-------------------------\n"); 21 } 22 23 // 4 releases pending. 24 // 最近的 @autoreleasepool 已释放 25 _objc_autoreleasePoolPrint(); 26 NSLog(@"-------------------------\n"); 27 28 } 29 30 // 2 releases pending. 31 _objc_autoreleasePoolPrint(); 32 } 33 34 return 0; 35 36 }
日志信息:hot是指当前页,因为对象过多则会有多个 pool page(你可以在自动释放池中遍历出几百个对象验证)
标签:函数,iOS,笔记,Person,objc,内存,BOUNDARY,page,POOL 来源: https://www.cnblogs.com/self-epoch/p/16310484.html