美文网首页
iOS 内存管理

iOS 内存管理

作者: 派大星的博客 | 来源:发表于2020-09-13 10:30 被阅读0次
    内存管理总结.png

    1. 内存布局

    20200324142841981.png
    • stack:方法调用
    • heap:通过alloc等分配的对象
    • bss:未初始化的全局变量
    • data:已初始化的全局变量
    • text:程序代码段

    2. 内存管理方案

    通过不同的场景入手:


    截屏2020-09-12 下午7.36.39.png

    ISA

    不同的架构对应不同的isa结构:

    # if __arm64__
    #   define ISA_MASK        0x0000000ffffffff8ULL
    #   define ISA_MAGIC_MASK  0x000003f000000001ULL
    #   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    #   define ISA_BITFIELD                                                      \
          uintptr_t nonpointer        : 1;                                       \
          uintptr_t has_assoc         : 1;                                       \
          uintptr_t has_cxx_dtor      : 1;                                       \
          uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
          uintptr_t magic             : 6;                                       \
          uintptr_t weakly_referenced : 1;                                       \
          uintptr_t deallocating      : 1;                                       \
          uintptr_t has_sidetable_rc  : 1;                                       \
          uintptr_t extra_rc          : 19
    #   define RC_ONE   (1ULL<<45)
    #   define RC_HALF  (1ULL<<18)
    
    # elif __x86_64__
    #   define ISA_MASK        0x00007ffffffffff8ULL
    #   define ISA_MAGIC_MASK  0x001f800000000001ULL
    #   define ISA_MAGIC_VALUE 0x001d800000000001ULL
    #   define ISA_BITFIELD                                                        \
          uintptr_t nonpointer        : 1;                                         \
          uintptr_t has_assoc         : 1;                                         \
          uintptr_t has_cxx_dtor      : 1;                                         \
          uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
          uintptr_t magic             : 6;                                         \
          uintptr_t weakly_referenced : 1;                                         \
          uintptr_t deallocating      : 1;                                         \
          uintptr_t has_sidetable_rc  : 1;                                         \
          uintptr_t extra_rc          : 8
    #   define RC_ONE   (1ULL<<56)
    #   define RC_HALF  (1ULL<<7)
    

    nonpointer : 1; 0表示是isa指针,1表示是isa结构体
    has_assoc : 1; 表示对象是否含有关联引用(associatedObject)
    has_cxx_dtor : 1; 表示当前对象是否有C++的析构函数(destructor),如果没有,释放时会快速的释放内存。
    shiftcls : 33; 当前对象类的指针
    magic : 6; magic的值调试器会用到,调试器根据magci的值判断当前对象已经初始过了,还是尚未初始化的空间。
    weakly_referenced : 1; 表示对象是否含有弱引用对象
    deallocating : 1; 表示对象是否正在释放
    has_sidetable_rc : 1; 表示对象的引用计数是否太大,如果太大,则需要用其他的数据结构来存
    extra_rc : 19; 对象的引用计数大于1,则会将引用计数的个数存到extra_rc里面。比如对象的引用计数为5,则extra_rc的值为4

    extra_rc和has_sidetable_c 可以一起理解。extra_rc用于存放引用计数的个数,extra_rc占8位,也就是最大表示255,当对象的引用计数个数超过257时,has_sidetable_rc的值应该为1。

    散列表

    SideTables.png SideTable.png

    SideTable的定义很清晰,有三个成员:

    • spinlock_t slock : 自旋锁,用于上锁/解锁 SideTable。
    • RefcountMap refcnts :以DisguisedPtr<objc_object>为key的hash表,用来存储OC对象的引用计数(仅在未开启isa优化 或 在isa优化情况下isa_t的引用计数溢出时才会用到)。
    • weak_table_t weak_table : 存储对象弱引用指针的hash表。是OC weak功能实现的核心数据结构。
    截屏2020-09-12 下午8.15.18.png 截屏2020-09-12 下午8.15.44.png

    SideTables.SideTable.weak_table.weak_entry_t 优秀博文

    20180920175152461.png
    struct SideTable {
        spinlock_t slock;           // 自旋锁,防止多线程访问冲突
        RefcountMap refcnts;        // 对象引用计数map
        weak_table_t weak_table;    // 对象弱引用map
    
        SideTable() {
            memset(&weak_table, 0, sizeof(weak_table));
        }
    
        ~SideTable() {
            _objc_fatal("Do not delete SideTable.");
        }
    
        void lock() { slock.lock(); }
        void unlock() { slock.unlock(); }
        void forceReset() { slock.forceReset(); }
    
        // Address-ordered lock discipline for a pair of side tables.
    
        template<HaveOld, HaveNew>
        static void lockTwo(SideTable *lock1, SideTable *lock2);
        template<HaveOld, HaveNew>
        static void unlockTwo(SideTable *lock1, SideTable *lock2);
    };
    

    spinlock_t 自旋锁

    Spinlock_t 是忙等的锁。
    适用于轻量级访问。(如:refCount +1 / -1)

    RefcountMap 引用计数表

    截屏2020-09-12 下午9.03.59.png

    size_t : (unsign long) 引用计数的值

    size_t.png

    weak_table_t 对象弱引用表

    weak_table_t.jpg

    3. 引用计数原理

    MRC

    MRC.png

    ARC

    ARC.png
    • alloc

    • retain


      retain的实现.png
    • release

    release的实现.png
    • retainCount
    retainCount实现.png
    • dealloc
    截屏2020-09-12 下午9.46.09.png
    - (void)dealloc {
        _objc_rootDealloc(self);
    }
    
    _objc_rootDealloc(id obj)
    {
        ASSERT(obj);
    
        obj->rootDealloc();
    }
    
    objc_object::rootDealloc()
    {
        if (isTaggedPointer()) return;
        object_dispose((id)this);
    }
    
    object_dispose.png
    object_dispose(id obj)
    {
        if (!obj) return nil;
    
        objc_destructInstance(obj);    
        free(obj);
    
        return nil;
    }
    
    objc_destructInstance.png
    void *objc_destructInstance(id obj) 
    {
        if (obj) {
            Class isa = obj->getIsa();
    
            if (isa->hasCxxDtor()) {
                object_cxxDestruct(obj);
            }
    
            if (isa->instancesHaveAssociatedObjects()) {
                _object_remove_assocations(obj);
            }
    
            objc_clear_deallocating(obj);
        }
    
        return obj;
    }
    
    clearDeallocating.png
    objc_object::clearDeallocating()
    {
        if (slowpath(!isa.nonpointer)) {
            // Slow path for raw pointer isa.
            sidetable_clearDeallocating();
        }
        else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
            // Slow path for non-pointer isa with weak refs and/or side table data.
            clearDeallocating_slow();
        }
    
        assert(!sidetable_present());
    }
    
    objc_object::sidetable_clearDeallocating()
    {
        SideTable& table = SideTables()[this];
    
        // clear any weak table items
        // clear extra retain count and deallocating bit
        // (fixme warn or abort if extra retain count == 0 ?)
        table.lock();
        RefcountMap::iterator it = table.refcnts.find(this);
        if (it != table.refcnts.end()) {
            if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {
                weak_clear_no_lock(&table.weak_table, (id)this);
            }
            table.refcnts.erase(it);
        }
        table.unlock();
    }
    

    清理顺序:

    1、C++ 析构函数
    2、移除关联对象
    3、weak reference 置nil
    4、RefcountMap[this] (引用计数值)擦除


    weak 弱引用

    弱引用编译.png 添加weak变量.png 清除weak变量.png

    👆请移步源码查看详细过程 👆


    4. 自动释放池

    IMG_4086.JPG

    黑幕背后的Autorelease • sunnyxx的技术博客

    总结:

    • 是以栈为结点通过双向链表的形式组合而成。
    • 是和线程一一对应的。
    • 在当次Runloop将要结束的时候调用AutoReleasePoolPage::pop()。
    • 多层嵌套就是多次插入哨兵对象(0 / nil)。
    • 在for循环中alloc图片数据等内存消耗较大的场景手动插入AutoReleasePool。

    5. 循环引用

    相关文章

      网友评论

          本文标题:iOS 内存管理

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