• [OC学习笔记]ARC与引用计数


    通过底层汇编看看ARC是怎么工作的

    首先自定义一个类Test
    该类有两个类方法,区别在于一个以new开头,调用者持有返回的对象,而create开头的则不持有。
    这个也是对应了ARC的方法命名规则:
    将内存管理语义在方法名中表示出来早已成为 Objective-C的惯例, 而ARC则将之确立为硬性规定。若方法名以下列词语开头, 则其返回的对象归调用者所有: allocnewcopymutableCopy。若调用上述开头的方法就要负责释放返回的对象。也就是说, 这些对象在MRC中需要你手动的进行释放。若方法名不以上述四个词语开头, 返回的对象就不需要你手动去释放, 因为在方法内部将会自动执行一次autorelease方法。

    @interface Test : NSObject
    
    + (instancetype)createTest;
    + (instancetype)newTest;
    
    @end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    @implementation Test
    
    + (instancetype)createTest {
        return [[self alloc] init];
    }
    
    + (instancetype)newTest {
        return [[self alloc] init];
    }
    
    @end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Test1

    [Test newTest];
    
    • 1

    请添加图片描述
    可以看出ARC为我们自动添加了release操作(objc_release),ARC优化后相当于:

    id temp = [Test newTest];
    objc_release(temp);
    
    • 1
    • 2

    Test2

    id temp = [Test newTest];
    
    • 1

    请添加图片描述
    可以看到这次出现了一个新的底层函数objc_storeStrong,相当于ARC在底层添加了objc_storeStrong(&temp, temp);,看看objc库中其具体实现:

    void
    objc_storeStrong(id *location, id obj)
    {
        id prev = *location;
        if (obj == prev) {
            return;
        }
        objc_retain(obj);
        *location = obj;
        objc_release(prev);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Test3

    self.test = [Test newTest];
    
    • 1

    请添加图片描述
    这里发了两次消息,新增的消息是发送setTest:的,调试可以看到,ARC在setTest:的加入了objc_storeStrong
    请添加图片描述
    相当于:

    {
    	id temp = [Test newTest];
        [self setTest:temp];
        objc_release(temp);
    }
    - (void)setTest:(Test *test) {
        objc_storeStrong(&_test, test);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Test4

    [Test createTest];
    
    • 1

    请添加图片描述
    请添加图片描述

    相当于:

    // Test
    + (instancetype)createTest {
        id temp = [self new];  
        return objc_autoreleaseReturnValue(temp); 
    } 
    // VC 
    objc_unsafeClaimAutoreleasedReturnValue([Test createTest]); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里可以看出不仅仅多了一个objc_unsafeClaimAutoreleasedReturnValue,并且在create中多了objc_autoreleaseReturnValue,这是因为ARC规则,无需手动释放的内部自动autorelease

    enum ReturnDisposition : bool {
        ReturnAtPlus0 = false, ReturnAtPlus1 = true
    };
    
    id 
    objc_autoreleaseReturnValue(id obj)
    {
        if (prepareOptimizedReturn(ReturnAtPlus1)) return obj;
    
        return objc_autorelease(obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    id
    objc_unsafeClaimAutoreleasedReturnValue(id obj)
    {
        if (acceptOptimizedReturn() == ReturnAtPlus0) return obj;
    
        return objc_releaseAndReturn(obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • objc_autoreleaseReturnValue这个函数的作用相当于代替我们手动调用 autorelease,创建了一个autorelease对象。编译器会检测之后的代码,根据返回的对象是否执行 retain操作,来设置全局数据结构中的一个标志位, 来决定是否会执行 autorelease操作。该标记有两个状态,ReturnAtPlus0代表执行 autorelease,以及ReturnAtPlus1代表不执行 autorelease
    • objc_unsafeClaimAutoreleasedReturnValue 这个函数的作用是对autorelease对象不做处理仅仅返回,对非autorelease对象调用objc_release函数并返回。所以本情景中它创建时执行了 autorelease操作了,就不会对其进行 release操作了。只是返回了对象,在合适的实际autoreleasepool会对其进行释放的。

    Test5

    id temp2 = [Test createTest];
    
    • 1

    请添加图片描述
    请添加图片描述

    id
    objc_retainAutoreleasedReturnValue(id obj)
    {
        if (acceptOptimizedReturn() == ReturnAtPlus1) return obj;
    
        return objc_retain(obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    objc_retainAutoreleasedReturnValue这个函数将替代 MRC中的 retain方法, 此函数也会检测刚才提到的那个标志位,如果为ReturnAtPlus0怎执行该对象的 retain操作,否则直接返回对象本身。
    在这个例子中, 由于代码中没有对对象进行保留,所以创建时objc_autoreleaseReturnValue函数设置的标志位状态是应该是ReturnAtPlus0。所以,该函数在此处是会进行 retain操作的。

    Test6

    self.test = [Test createTest];
    
    • 1

    请添加图片描述

    请添加图片描述
    与前面的类似。

    ARC对于修饰符的优化

    __strong

    与Test2相同

    __weak

    __weak id temp3 = [Test newTest];
    
    • 1

    请添加图片描述
    相当于:

    id temp = [Test newTest]; 
    objc_initWeak(&temp3, temp);
    objc_release(temp);
    objc_destroyWeak(&temp3);
    
    • 1
    • 2
    • 3
    • 4

    这个过程就是weak指针的一个周期,从创建到销毁。这上面两个新的runtime函数,objc_initWeakobjc_destroyWeak。这两个函数就是负责创建__weak指针和销毁__weak指针的。其实, 这两个函数内部都引用另一个runtime函数,storeWeak,它是和storeStrong对应的一个函数。

    id
    objc_initWeak(id *location, id newObj)
    {
        if (!newObj) {
            *location = nil;
            return nil;
        }
    
        return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
            (location, (objc_object*)newObj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    void
    objc_destroyWeak(id *location)
    {
        (void)storeWeak<DoHaveOld, DontHaveNew, DontCrashIfDeallocating>
            (location, nil);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    __unsafe_unretained

    请添加图片描述
    仅仅添加了objc_release__unsafe_unretained类型,不具有所有权,所以只是简单的指针赋值, 没有runtime的函数使用。当临时变量temp销毁后, 指针仍然是指向那块内存, 所以是不安全的。正如其名,unretainedunsafe

    __autoreleasing

    请添加图片描述
    使用__autorelease修饰后, 就相当于为其添加一个autorelease,当autoreleasepool销毁的时候,将其释放掉。

    objc_retain的内部逻辑

    id 
    objc_retain(id obj)
    {
        if (_objc_isTaggedPointerOrNil(obj)) return obj;
        return obj->retain();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    static inline bool
    _objc_isTaggedPointerOrNil(const void * _Nullable ptr)
    {
        // this function is here so that clang can turn this into
        // a comparison with NULL when this is appropriate
        // it turns out it's not able to in many cases without this
        return !ptr || ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果是TaggedPointer对象或者nil直接返回。接着向下看:

    inline id 
    objc_object::retain()
    {
        ASSERT(!isTaggedPointer());
    
        return rootRetain(false, RRVariant::FastOrMsgSend);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    非TaggedPointer对象,继续操作:

    ALWAYS_INLINE id
    objc_object::rootRetain(bool tryRetain, objc_object::RRVariant variant)
    {
        // 如果是 Tagged Pointer 则直接返回 this (Tagged Pointer 不参与引用计数管理,它的内存在栈区,由系统处理)
        if (slowpath(isTaggedPointer())) return (id)this;
        // 临时变量,标记 SideTable 是否加锁
        bool sideTableLocked = false;
        // 临时变量,标记是否需要把引用计数迁移到 SideTable 中
        bool transcribeToSideTable = false;
    
        // 记录 objc_object 之前的 isa
        isa_t oldisa;
        // 记录 objc_object 修改后的 isa
        isa_t newisa;
        
        // 似乎是原子性操作,读取 &isa.bits。(&为取地址)
        oldisa = LoadExclusive(&isa.bits);
    
        if (variant == RRVariant::FastOrMsgSend) {
            // These checks are only meaningful for objc_retain()
            // They are here so that we avoid a re-load of the isa.
            // 这些检查仅对objc_retain()有意义
            // 它们在这里,以便我们避免重新加载isa。
            if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) {
                ClearExclusive(&isa.bits);
                if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
                    return swiftRetain.load(memory_order_relaxed)((id)this);
                }
                return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(retain));
            }
        }
    
        if (slowpath(!oldisa.nonpointer)) {
            // a Class is a Class forever, so we can perform this check once
            // outside of the CAS loop
            if (oldisa.getDecodedClass(false)->isMetaClass()) {
                ClearExclusive(&isa.bits);
                return (id)this;
            }
        }
        
        // 循环结束的条件是 slowpath(!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits))
        // StoreExclusive 函数,如果 &isa.bits 与 oldisa.bits 的内存内容相同,则返回 true,并把 newisa.bits 复制到 &isa.bits,
        // 否则返回 false,并把 &isa.bits 的内容加载到 oldisa.bits 中。
        // 即 do-while 的循环条件是指,&isa.bits 与 oldisa.bits 内容不同,如果它们内容不同,则一直进行循环,
        // 循环的最终目的就是把 newisa.bits 复制到 &isa.bits 中。
        // return __c11_atomic_compare_exchange_weak((_Atomic(uintptr_t) *)dst,
        //                                          &oldvalue, value, __ATOMIC_RELAXED, __ATOMIC_RELAXED)
        
        // _Bool atomic_compare_exchange_weak( volatile A *obj, C* expected, C desired );
        // 定义于头文件 
        // 原子地比较 obj 所指向对象的内存的内容与 expected 所指向的内存的内容,若它们相等,则以 desired 替换前者(进行读修改写操作)。
        // 否则,将 obj 所指向的实际内存内容加载到 *expected (进行加载操作)。
        
        do {
            // 默认不需要转移引用计数到 SideTable
            transcribeToSideTable = false;
            
            // 赋值给 newisa(第一次进来时 &isa.bits, oldisa.bits, newisa.bits 三者是完全相同的)
            newisa = oldisa;
            
            // 如果 newisa 不是优化的 isa (元类的 isa 是原始的 isa (Class cls))
            if (slowpath(!newisa.nonpointer)) {
                
                // 在 mac、arm64e 下不执行任何操作,只在 arm64 下执行 __builtin_arm_clrex();
                // 在 arm64 平台下,清除对 &isa.bits 的独占访问标记。
                ClearExclusive(&isa.bits);
                
                // 如果需要 tryRetain 则调用 sidetable_tryRetain 函数,并根据结果返回 this 或者 nil。
                // 执行此行之前是不需要在当前函数对 SideTable 加锁的
                // sidetable_tryRetain 返回 false 表示对象已被标记为正在释放,
                // 所以此时再执行 retain 操作是没有意义的,所以返回 nil。
                if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
                // 如果不需要 tryRetain 则调用 sidetable_retain()
                else return sidetable_retain(sideTableLocked);
            }
            // don't check newisa.fast_rr; we already called any RR overrides
            // 不要检查 newisa.fast_rr; 我们已经调用所有 RR 的重载。
            // 如果 tryRetain 为真并且 objc_object 被标记为正在释放 (newisa.deallocating),则返回 nil
            if (slowpath(newisa.isDeallocating())) {
                ClearExclusive(&isa.bits);
                // SideTable 处于加锁状态
                if (sideTableLocked) {
                    ASSERT(variant == RRVariant::Full);
                    // 进行解锁
                    sidetable_unlock();
                }
                // 需要 tryRetain
                if (slowpath(tryRetain)) {
                    return nil;
                } else {
                    return (id)this;
                }
            }
            // 下面就是 isa 为 nonpointer,并且没有被标记为正在释放的对象
            uintptr_t carry;
            // bits extra_rc 自增
            
            // x86_64 平台下:
            // # define RC_ONE (1ULL<<56)
            // uintptr_t extra_rc : 8
            // extra_rc 内容位于 56~64 位
            newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++
            // 如果 carry 为 true,表示要处理引用计数溢出的情况
            if (slowpath(carry)) {
                // newisa.extra_rc++ overflowed
                // 如果 variant 不为 Full,
                // 则调用 rootRetain_overflow(tryRetain) 它的作用就是把 variant 传为 Full
                // 再次调用 rootRetain 函数,目的就是 extra_rc 发生溢出时,我们一定要处理
                if (variant != RRVariant::Full) {
                    ClearExclusive(&isa.bits);
                    return rootRetain_overflow(tryRetain);
                }
                // Leave half of the retain counts inline and 
                // prepare to copy the other half to the side table.
                // 将 retain count 的一半留在 inline,并准备将另一半复制到 SideTable.
                if (!tryRetain && !sideTableLocked) sidetable_lock();
                // 整个函数只有这里把 sideTableLocked 置为 true
                sideTableLocked = true;
                // 标记需要把引用计数转移到 SideTable 中
                transcribeToSideTable = true;
                // x86_64 平台下:
                // uintptr_t extra_rc : 8
                // # define RC_HALF  (1ULL<<7) 二进制表示为: 0b 1000,0000
                // extra_rc 总共 8 位,现在把它置为 RC_HALF,表示 extra_rc 溢出
                newisa.extra_rc = RC_HALF;
                // 把 has_sidetable_rc 标记为 true,表示 extra_rc 已经存不下该对象的引用计数,
                // 需要扩张到 SideTable 中
                newisa.has_sidetable_rc = true;
            }
        } while (slowpath(!StoreExclusive(&isa.bits, &oldisa.bits, newisa.bits)));
    
        if (variant == RRVariant::Full) {
            if (slowpath(transcribeToSideTable)) {
                // Copy the other half of the retain counts to the side table.
                // 复制 retain count 的另一半到 SideTable 中。
                sidetable_addExtraRC_nolock(RC_HALF);
            }
            // 如果 tryRetain 为 false 并且 sideTableLocked 为 true,则 SideTable 解锁
            if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
        } else {
            ASSERT(!transcribeToSideTable);
            ASSERT(!sideTableLocked);
        }
        // 返回 this
        return (id)this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • TaggedPointer:值存在指针内,直接返回。
    • !newisa.nonpointer:未优化的 isa ,使用sidetable_retain()
    • newisa.nonpointer:已优化的 isa , 这其中又分 extra_rc 溢出和未溢出的两种情况。
      ①未溢出时,isa.extra_rc + 1
      ②溢出时,将 isa.extra_rc 中一半值转移至sidetable中,然后将isa.has_sidetable_rc设置为true,表示使用了sidetable来计算引用次数

    objc_release的内部逻辑

    void 
    objc_release(id obj)
    {
        if (_objc_isTaggedPointerOrNil(obj)) return;
        return obj->release();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    inline void
    objc_object::release()
    {
        ASSERT(!isTaggedPointer());
    
        rootRelease(true, RRVariant::FastOrMsgSend);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    ALWAYS_INLINE bool
    objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)
    {
        if (slowpath(isTaggedPointer())) return false;
        // 标记 SideTable 是否加锁了
        bool sideTableLocked = false;
        // 临时变量存放旧的 isa 和字段修改后的 isa
        isa_t newisa, oldisa;
        // 以原子方式读到 &isa.bits 的数据
        oldisa = LoadExclusive(&isa.bits);
    
        if (variant == RRVariant::FastOrMsgSend) {
            // These checks are only meaningful for objc_release()
            // They are here so that we avoid a re-load of the isa.
            if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) {
                ClearExclusive(&isa.bits);
                if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
                    swiftRelease.load(memory_order_relaxed)((id)this);
                    return true;
                }
                ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(release));
                return true;
            }
        }
    
        if (slowpath(!oldisa.nonpointer)) {
            // a Class is a Class forever, so we can perform this check once
            // outside of the CAS loop
            if (oldisa.getDecodedClass(false)->isMetaClass()) {
                ClearExclusive(&isa.bits);
                return false;
            }
        }
    
    retry:
        do {
            // 把 oldisa 赋值给 newisa,此时 isa.bits/oldisa/newisa 三者是相同的
            newisa = oldisa;
            if (slowpath(!newisa.nonpointer)) {
                // 如果对象的 isa 只是原始指针 (Class isa/Class cls)
                            
                // __arm64__ && !__arm642__ 平台下,取消 &isa.bits 的独占访问标记
                // x86_64 下什么都不需要做,对它而言上面的 LoadExclusive 也只是一个原子读取 (atomic_load)
                ClearExclusive(&isa.bits);
                return sidetable_release(sideTableLocked, performDealloc);
            }
            // 正在dealloc
            if (slowpath(newisa.isDeallocating())) {
                ClearExclusive(&isa.bits);
                if (sideTableLocked) {
                    ASSERT(variant == RRVariant::Full);
                    sidetable_unlock();
                }
                return false;
            }
    
            // don't check newisa.fast_rr; we already called any RR overrides
            // 不要检查 newisa.fast_rr; 我们之前已经调用过所有 RR 的重载
            uintptr_t carry;
            newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc--
            // 如果发生了下溢出的话,要进行处理,如果没有发生的话就是结束循环,解锁并执行 return false;
            if (slowpath(carry)) {
                // don't ClearExclusive()
                goto underflow;
            }
            // 这里结束循环的方式同 rootRetain 函数,都是为了保证 isa.bits 能正确修改
            // StoreExclusive 和 StoreReleaseExclusive 的区别在于 memory_order_relaxed 和 memory_order_release
            // 可参考 https://en.cppreference.com/w/cpp/atomic/memory_order
                
            // 当 &isa.bits 与 oldisa.bits 相同时,把 newisa.bits 复制给 &isa.bits,并返回 true
            // 当 &isa.bits 与 oldisa.bits 不同时,
            // 把 oldisa.bits 复制给 &isa.bits, 并返回 false (此时会继续进行 do wehile 循环)
        } while (slowpath(!StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits)));
    
        if (slowpath(newisa.isDeallocating()))
            goto deallocate;
        if (variant == RRVariant::Full) {
            if (slowpath(sideTableLocked)) sidetable_unlock();
        } else {
            ASSERT(!sideTableLocked);
        }
        return false;
    
     underflow:
        // newisa.extra_rc-- underflowed: borrow from side table or deallocate
        // newisa.extra_rc--下溢:从side table 借取或取消分配
        // abandon newisa to undo the decrement
        // 放弃 newisa 以撤消递减
        newisa = oldisa;
    
        if (slowpath(newisa.has_sidetable_rc)) {
            // 有side table
            if (variant != RRVariant::Full) {
                ClearExclusive(&isa.bits);
                // 会再进来一次,这次 variant 变成 Full
                return rootRelease_underflow(performDealloc);
            }
    
            // Transfer retain count from side table to inline storage.
            // 将保留计数从 side table 传输到内联存储。
            if (!sideTableLocked) {
                ClearExclusive(&isa.bits);
                sidetable_lock();
                sideTableLocked = true;
                // Need to start over to avoid a race against 
                // the nonpointer -> raw pointer transition.
                oldisa = LoadExclusive(&isa.bits);
                goto retry;
            }
    
            // Try to remove some retain counts from the side table.
            // 尝试从 side table 中删除一些保留计数。
            auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
    
            bool emptySideTable = borrow.remaining == 0; // we'll clear the side table if no refcounts remain there
            // 如果没有引用计数,我们将清除side table
            if (borrow.borrowed > 0) {
                // Side table retain count decreased.
                // SideTable 引用计数 减少。
                // Try to add them to the inline count.
                // 尝试将借来的引用计数增加到 extra_rc 中。
                bool didTransitionToDeallocating = false;
                // 赋值。(包含减 1 的操作)
                newisa.extra_rc = borrow.borrowed - 1;  // redo the original decrement too
                // 重新判断是否溢出(是否需要side table)
                newisa.has_sidetable_rc = !emptySideTable;
    
                // 原子保存修改后的 isa.bits
                bool stored = StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits);
    
                // 如果失败的话
                if (!stored && oldisa.nonpointer) {
                    // Inline update failed.
                    // extra_rc 更新失败。
                    
                    // Try it again right now. This prevents livelock on LL/SC 
                    // architectures where the side table access itself may have 
                    // dropped the reservation.
                    // 立即进行重试。
                    // 这样可以防止在 LL/SC体系结构上发生 livelock,在这种情况下 SideTable 访问本身可能已取消预留。
                    // 活锁可参考: https://www.zhihu.com/question/20566246
    
                    uintptr_t overflow;
                    // 把借来的引用计数增加到 extra_rc 中
                    newisa.bits =
                        addc(oldisa.bits, RC_ONE * (borrow.borrowed-1), 0, &overflow);
                    newisa.has_sidetable_rc = !emptySideTable;
                    if (!overflow) {
                        // 如果还是失败的话,继续向下走
                        stored = StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits);
                        if (stored) {
                            didTransitionToDeallocating = newisa.isDeallocating();
                        }
                    }
                }
    
                if (!stored) {
                    // Inline update failed.
                    // 如果还是失败了。
                    // Put the retains back in the side table.
                    // 把从 SideTable 借来的引用计数还放回到 SideTable 中去。
                    ClearExclusive(&isa.bits);
                    sidetable_addExtraRC_nolock(borrow.borrowed);
                    oldisa = LoadExclusive(&isa.bits);
                    // 然后直接 goto retry; 进行全盘重试
                    goto retry;
                }
    
                // Decrement successful after borrowing from side table.
                if (emptySideTable)
                    sidetable_clearExtraRC_nolock();
    
                if (!didTransitionToDeallocating) {
                    if (slowpath(sideTableLocked)) sidetable_unlock();
                    return false;
                }
            }
            else {
                // Side table is empty after all. Fall-through to the dealloc path.
            }
        }
    
    deallocate:
        // Really deallocate.
    
        ASSERT(newisa.isDeallocating());
        ASSERT(isa.isDeallocating());
    
        if (slowpath(sideTableLocked)) sidetable_unlock();
        
        // 原子性线程栅栏?
        __c11_atomic_thread_fence(__ATOMIC_ACQUIRE);
    
        if (performDealloc) {
            // 如果 performDealloc 为 true,则以消息发送的方式调用 dealloc
            ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
        }
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • TaggedPointer: 直接返回 false
    • !nonpointer: 未优化的 isa 执行 sidetable_release
    • nonpointer:已优化的 isa ,分下溢和未下溢两种情况。
      ①未下溢: extra_rc--
      ②下溢:从 sidetable 中借位给 extra_rc 达到半满,如果无法借位,则说明引用计数归零需要进行释放。其中借位时可能保存失败会不断重试。

    retainCount的内部逻辑

    - (NSUInteger)retainCount {
        return _objc_rootRetainCount(self);
    }
    
    • 1
    • 2
    • 3
    uintptr_t
    _objc_rootRetainCount(id obj)
    {
        ASSERT(obj);
    
        return obj->rootRetainCount();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    inline uintptr_t 
    objc_object::rootRetainCount()
    {
        if (isTaggedPointer()) return (uintptr_t)this;
    
        sidetable_lock();
        isa_t bits = __c11_atomic_load((_Atomic uintptr_t *)&isa.bits, __ATOMIC_RELAXED);
        if (bits.nonpointer) {
            // 引用计数 = extra_rc
            uintptr_t rc = bits.extra_rc;
            // 如果side table中有值
            if (bits.has_sidetable_rc) {
                // 再加上side table中的引用计数
                rc += sidetable_getExtraRC_nolock();
            }
            sidetable_unlock();
            return rc;
        }
    
        sidetable_unlock();
        // 不是优化型isa指针, 引用计数存储在SideTable中,获取并返回
        return sidetable_retainCount();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    从0到1搭建一个vue项目
    【Django】Django Class-Based Views (CBV) 与 DRF APIView 的区别解析
    【Spring系列】- 手写模拟Spring框架
    Feign的简介及使用
    个人关于ChatGPT的用法及建议
    vue3+ts 组合式api中(setup)如何使用getCurrentInstance,以及用它替代this
    [vxe-table] 合并行后滚动错位
    MCE | 癌相关基因 ALK 参与胖瘦调节
    javascript: Bubble Sort
    使用jsqlparser创建MySQL建表语句
  • 原文地址:https://blog.csdn.net/weixin_52192405/article/details/125975678