美文网首页
iOS面试之内存管理

iOS面试之内存管理

作者: iOS王的男人 | 来源:发表于2021-03-25 15:07 被阅读0次

    原文地址https://www.jishudog.com/8744/html

    推荐👇:

    推荐作者:iOS的火影乱斗

    地址

    内存布局


    iOS程序下内存布局

    不同内存布局区域的含义
    stack(栈):方法调用
    heap(堆):通过alloc等分配的对象
    bss:未初始化的全局变量
    data:已初始化的全局变量
    text:程序代码

    内存管理方案

    • taggedPointer
    • NONPointer_ISA
    • 散列表(很复杂的数据结构,引用计数表、弱引用表)
    散列表
    • SideTables()(非嵌入式系统中包含64个SideTable),实际是一个哈希表,通过对象的指针找到对应的引用计数表或弱引用表,在哪一个SideTable中
    • SideTable结构
      包含自旋锁 引用计数表 弱引用表
    • 为什么不是一个SideTable?
      存在效率问题,如果多个对象在对同一张表进行引用计数时,就会等待前一个对象操作结束才能操作。引用分离锁的方案,可以提高效率
    • 如果实现快速分流?(哈希查找的过程)
      根据对象的地址,通过一个均匀散列函数的计算就可以得到数组下标索引值

    散列表中数据结构

    • 自旋锁(Spinlock_t
      是一种忙等的锁(当前锁已被其他线程获取,就会不断的探测这个锁是否被释放)
      适用于轻量访问
    • 引用计数表(RefcountMap
      ptr ——> DisguisedPtr(obj) ——>size_t
      提高查找效率,插入和获取都是通过同一个哈希算法,避免了数组遍历
    • 弱引用表(weal_table_t
      ptr ——> Hash函数——>value

    ARC&&MRC

    1. MRC 手动引用计数
      • alloc
      • retain
      • release
      • retainCount
      • autorelease
      • dealloc

    2.ARC 自动引用计数

    • ARC是LLVM和Runtime协作的结果
    • ARC禁止手动调用retain、release、retainCount、dealloc
    • ARC中新增weak、strong属性关键字

    引用计数

    • alloc
      经过一系列调用,最终调用的C函数malloc,此时并没有设置引用计数为1(但是通过retainCount得知是1,在后面会讲到)

    • retain
      经过两次Hash查找,找到对应的引用计数值,然后进行+1的操作

    • release
      经过两次Hash查找,找到对应的引用计数值,然后进行-1的操作

    • retainCount
      经过两次Hash查找,找到对应的引用计数值,然后与1相加(因此刚alloc的对象,在对应的引用计数表中实际是没有这个映射的)

    • dealloc
      这里有一个iOS交流圈:891 488 181 不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

      判断时候可以释放的条件(五个条件缺一不可)

      • 没有使用nonpointer_isa
      • 没有weak指针指向
      • 没有有关联对象
      • 没有使用ARC或者涉及C++
      • 当前对象的引用计数没有通过SideTable中的引用计数表来存储的

    [图片上传失败...(image-584a89-1608785619322)]

    object_dospose()函数内部实现分析


    clearDeallocating()内部实现

    弱引用


    weak变量的添加过程

    如何添加weak变量的?
    对象指针在经过编译器的编译之后调用objc_initweak(),然后storeweak()方法,经过一系列的函数调用,最终在weak_register_no_lock()进行弱引用变量的添加,通过hash算法位置查找,如果已经存在当前对象对应的弱引用数组,则直接加进去,如果没有则创建新个新的弱引用数组,存放新的weak指针


    系统如何实现将废弃的weak指针置为nil

    系统如何实现将废弃的weak指针置为nil?
    当对象被dealloc后废弃之后,会调用弱引用清除的相关函数。然后在函数实现中,根据当前对象指针,查找弱引用表,把当前对象对应的弱引用都拿出来,然后遍历所有的弱引用指针置为nil

    自动释放池

    AutoreleasePool的实现原理是怎么样的?

    AutoreleasePool是以栈为结点,通过双向链表的形式组合而成的数据结构。编译器会将@autoreleasepool{}改写,如下 图。实际objc_autoreleasePoolPop函数在内部做了pop操作,批量将autoreleasepool中的所有的对象都会做一次release操作


    编译器改写@autoreleasepool{}

    下面对上面的主要函数进行一个简单的说明

    AutoreleasePool的结构
    • 是以栈为结点通过双向链表的形式组合而成
    • 是和线程一一对应的

    什么是双向链表?


    双向 链表结构

    [obj autorelease]的实现(对象加入自动释放池)

    先判断当前next指针是否指向栈顶,如果不是直接加入;如果是,则增加一个栈结点到链表上,在新的栈添加对象;移动next指针

    AutoreleasePoolPage::push实现流程(释放池多层嵌套)
    • 插入哨兵对象

    AutoreleasePoolPage::pop实现流程(与push相反)
    • 根据传入的哨兵对象找到对应的位置
    • 给上次push操作之后添加的对象依次添加release消息
    • 回退next指针到正确的位置
    AutoreleasePool为何可以嵌套使用?

    多次插入哨兵对象,也就是对一个新的releasePool的创建,如果当前栈没有满,则不需要创建新的page,如果满了,新增一个栈节点

    下面这个图中,array对象在什么时候释放呢?

    答:在档次runloop将要结束的时候调用AutoreleasePoolPage:pop(),对array对象执行release操作

    AutoreleasePool的使用场景?

    在for循环中,alloc图片数据等内存消耗较大的场景手动插入autoreleasePool,每一次for循环都进行一次内存的释放,降低内存消耗

    循环引用

    • 自循环引用
    • 相互循环引用
    • 多循环引用

    自循环引用 对自身强持有



    相互循环引用



    多循环引用
    常见的循环引用以及破除方法:
    • 代理(delegate)
    • block
    • NSTimer
    • 大环引用
    如何破除循环引用?
    • 避免产生循环引用
    • 在合适的时机手动断环
    具体解决方案有哪些?
    • __weak
    • __block
    • __unsafe_unretained(与weak等效)
    __block在ARC和MRC条件下的区别
    • MRC下,__block修饰对象不会增加其引用计数,避免了循环引用
    • ARC下,__block修饰对象会被强引用,无法避免,需手动破环
    __unsafe_unretained破解
    • 修饰对象不会增加其引用计数,避免了循环引用
    • 如果找修饰对象在某一事迹被释放,产生悬空指针
    循环引用的示例?(平时开发时是否有遇到循环引用,又是怎么解决的?)
    1. Block使用示例(在后面block讲解时)
    2. NSTimerd的循环引用问题

    文章到这里就结束了,你也可以私信我及时获取面试资料。如果你有什么意见和建议欢迎给我留言。

    相关文章

      网友评论

          本文标题:iOS面试之内存管理

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