美文网首页内存OC 底层iOS 进阶
内存管理 - 引用计数 weak指针

内存管理 - 引用计数 weak指针

作者: 曹来东 | 来源:发表于2018-09-18 14:02 被阅读31次

引用计数的存储

  • 在64bit中,引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable类中
  • refcnts是一个存放着对象引用计数的散列表
    image.png
    优化过的isa指针是一个union共用体.里面最后的19位存储着对象的引用计数.如果这19位不够存储,共用体内的has_sidetable_rc成员变量的值会变成1.
    image.png
    image.png
  • NSObject.mm源码 - 引用计数
uintptr_t
_objc_rootRetainCount(id obj)
{
    assert(obj);

    return obj->rootRetainCount();
}

inline uintptr_t 
objc_object::rootRetainCount()
{
    //是一个TaggedPointer 不是一个OC对象
    if (isTaggedPointer()) return (uintptr_t)this;

    sidetable_lock();
    isa_t bits = LoadExclusive(&isa.bits);
    ClearExclusive(&isa.bits);
    if (bits.nonpointer) {//优化过的isa指针,引用计数这样获取
        uintptr_t rc = 1 + bits.extra_rc;//19位够存储,直接取出引用计数 + 1
        if (bits.has_sidetable_rc) {//如果19位不够存储,has_sidetable_rc值为1
            rc += sidetable_getExtraRC_nolock();//从sidetable中获取额外的引用计数累加
        }
        sidetable_unlock();
        return rc;//返回该对象的引用计数.
    }

    sidetable_unlock();
//没有优化过的isa指针,直接从sidetable中获取引用计数
    return sidetable_retainCount();
}

dealloc weak指针实现原理

  • 当一个对象要释放时,会自动调用dealloc,接下的调用轨迹是
    dealloc
    _objc_rootDealloc
    rootDealloc
    object_dispose
    objc_destructInstance、free


    image.png

ARC工作内容:

  • LLVM编译器生成 内存管理代码 retain release
  • RunTime对弱引用进行置空 等操作.

自动释放池

  • 自动释放池的主要底层数据结构是:__AtAutoreleasePool、AutoreleasePoolPage
  • 调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的
  • 源码分析
    clang重写@autoreleasepool
    objc4源码:NSObject.mm


    image.png
  • 每个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址
  • 所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起


    image.png

AutoreleasePoolPage的结构

  • 调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址
  • 调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY
  • id *next指向了下一个能存放autorelease对象地址的区域

Runloop和Autorelease

  • iOS在主线程的Runloop中注册了2个Observer
  • 第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
  • 第2个Observer
    监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
  • 监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()

autorelease对象在什么时机会被调用release

当前所处的RunLoop休眠之前,或退出前会调用pop操作,来释放autorelease对象.

方法里有局部对象, 出了方法后会立即释放吗

如果编译器对该局部对象生成的内存管理代码是autoreleasepool该对象不会立刻释放,需要在RunLoop休眠之前,或退出前会调用pop操作,来释放autorelease对象;如果编译器对该局部对象生成的内存管理代码是在方法结束插入relase代码,则该对象出了方法会立即释放.

相关文章

  • 内存管理 - 引用计数 weak指针

    引用计数的存储 在64bit中,引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable类中 r...

  • iOS ,内存分布、内存管理 、isa 指针,散列表(引用计数表

    iOS ,内存分布、内存管理 、isa 指针,散列表(引用计数表,弱引用表) 内存管理方案 1.taggedPoi...

  • Swift 2 学习笔记 21.内存管理

    课程来自慕课网liuyubobobo老师 内存管理 deinit 引用计数 强引用循环和weak unowned ...

  • __weak 修饰符

    SideTables SideTables 是全局表,管理着对象的引用计数和weak引用指针,每个对象在此表中都有...

  • 引用计数和weak原理

    引用计数 为了管理所有对象的引用计数和weak指针,苹果创建了一个全局的SideTables,虽然名字后面有个"s...

  • @property关键字

    1.weak: weak,弱指针,不会让引用计数器+1,如果指向对象被销毁,指针会自动置nil weak原理: r...

  • weak和assign的区别

    都不是强指针(不是强引用),不能保住对象的命weak:__weak弱指针,不会让引用计数器+1,如果指向对象被销毁...

  • 关情纸尾---OC-内存管理

    一、引用计数器 二、野指针和空指针 三、set方法的内存管理 四、property的内存管理(代替oc对象的set...

  • weak实现原理

    weak弱引用,修饰的对象引用计数不会+1,在引用计数为0时,把指针置为nil,避免野指针。通常用来修饰deleg...

  • OC总结(二)

    一.内存问题(1).内存溢出(2).野指针(过度释放)二.内存管理方式: (1)MRC:手动管理引用计数.对对象完...

网友评论

    本文标题:内存管理 - 引用计数 weak指针

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