自动释放池
objc下层c++代码
生成c++代码查看
- clang -rewrite-objc main.m -o main.cpp
- 脚本直接直接配置到测试工程里
image.png
脚本直接生成c++代码 并打开
image.png
选择脚本 build,xcode直接弹窗打开c++代码
image.png
查找autorelease相关c++代码
image.png
- 全局查找 __AtAutoreleasePool 是个结构体
image.png
其实说白了就是结构体(自动释放池)构造,析构
其实说白了就是结构体(自动释放池)构造,析构
- 自动释放池作用域调整下代码
image.png
构造 objc_autoreleasePoolPush() 压栈
析沟 objc_autoreleasePoolPop(void *) 弹出栈
根据c++代码分析大致了解到,自动释放池其实就是一块作用域时机,作用域开始时构造,作用域结束时析构回收 主要是个栈结构
汇编查看
image.png
image.png
通过汇编,结果更直观,压栈,执行逻辑, 出栈
汇编 进入符号 objc_autoreleasePoolPush 最终得到符号所在的dyld
image.png
发现 objc_autoreleasePoolPush 符号存在于objc源码中,所以我们进入源码
没有源码环境?快速配置一个出来
打开源码调试工程
查找符号 objc_autoreleasePoolPush
image.png
image.png
-
如果就这样分析,还是一股脑儿就是代码,没什么直观意识,能查看到具体结构信息最好
关闭arc
image.png
既然提到了打印信息,那么就看源码里有没有相关的调试打印函数,既然有调试,应该会有,拿来用就可以了
前后多看些范围代码,发现了打印函数
image.png
既然C函数,我们可以声明extern来使用
image.png
- 编译运行
image.png
image.png
image.png
image.png
image.png
非arc下,autorelease - 对象才会放入池子
- 如果加个循环
image.png
image.png
image.png
image.png
这时候 其实可以看出关键点了 根据打印逻辑回看源码
AutoreleasePoolPage: AutoreleasePoolPageData
image.png
可以看出是个双向链表 (nil <- page <-> page <-> page <-> page -> nil)
image.png
AutoreleasePoolPage: push()
image.png
image.png
image.png
image.png
释放池push操作 分析一下
-
释放池是分页设计,就像内存分页概念一样,如果不分页,一下子要面对池子里的一坨很大的数据,人是无法处理超级多的复杂的事情的,这儿自动释放池也一样
-
不分页的设计会造成池子里对象么次操作 都需要检索整个池子,而池子对象可能很多,效率不高
-
只有分页对于栈式结构来说,每次操作只在有限长度栈结构内,超过就一页一页pop,之前被压在hot页下面的不活动页变成hot,每次操作只需要检索一小块数据对象
-
对于嵌套释放池,不分页设计就没有了渐进式内存处理,池子要么整个内存,要么整个释放,但其实从应用逻辑业务角度来看,用户的操作是一个一个访问具体功能,分页才更合理
-
自动释放池整体可以理解为两层栈结构
-
外层把一个个page看作一个个单元,page压栈出栈的过程,page大小是固定的,顶层的page为活动的page,也就是当前操作的page
-
page内部也是一个栈结构,object压栈出栈,object可能是常规对象,也可能是边界,用于区分是不是嵌套了池子
-
池子可能跨越了多个page,也可能就在一个page里,不重要,看边界在哪儿
-
分析page大小
根据上面的1024次循环 构建1024个对象,打印结果出现两次 page full标识,也就是有3页,两个满页
hot page未满,有15个对象
也就是说每个page ((1024-15) + 1) / 2 = 505 个对象(每个对象指针8字节)【+1是因为还有一个边界8字节】
505 * 8 = 4040字节 ---- 4k == 4096字节 ----- 差56字节? 差在了哪儿?
image.pngimage.png
可以理解为 每个page有一个magic_t 结构的头,占用16字节 page大小4k得证
自动释放池嵌套
image.png image.png image.pngimage.png
自动释放池扩展
image.png没有autorelease,对象并没有进入释放池 当前是在非ARC下
现在切回ARC
image.png其实 alloc new copy multablecopy相关前缀 在llvm编译期间不会加入到释放池
自动释放池 pop操作与push相反,就不赘述了, 简单来讲就是 从hotpage开始遍历release对象,然后page->parent 找到code page设置为hot page,当前hotpage kill