自动释放池

作者: erlich | 来源:发表于2022-06-20 23:54 被阅读0次

    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.png
    image.png

    可以理解为 每个page有一个magic_t 结构的头,占用16字节 page大小4k得证

    自动释放池嵌套

    image.png image.png image.png
    image.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

    相关文章

      网友评论

        本文标题:自动释放池

        本文链接:https://www.haomeiwen.com/subject/tapjvrtx.html