iOS——retain和release底层原理

打印 上一主题 下一主题

主题 572|帖子 572|积分 1716

retain实现原理

retain的源码:
  1. //使用此方法等价于使用[this retain]
  2. inline id
  3. objc_object::retain()
  4. {
  5.   //确保对象不是tagged pointer
  6.     ASSERT(!isTaggedPointer());
  7.     return rootRetain(false, RRVariant::FastOrMsgSend);
  8. }
复制代码
  1. ALWAYS_INLINE id
  2. objc_object::rootRetain()
  3. {
  4.   //分为快速路径和慢速路径,以优化性能和处理溢出情况。
  5.     return rootRetain(false, RRVariant::Fast);
  6. }
复制代码
  1. ALWAYS_INLINE id
  2. objc_object::rootRetain(bool tryRetain, objc_object::RRVariant variant)
  3. {
  4.     if (slowpath(isTaggedPointer())) return (id)this;
  5.     bool sideTableLocked = false;
  6.     bool transcribeToSideTable = false;
  7.   //为什么有isa?因为需要对引用计数+1,即retain+1,而引用计数存储在isa的bits中,需要进行新旧isa的替换
  8.     isa_t oldisa;
  9.     isa_t newisa;
  10.     oldisa = LoadExclusive(&isa.bits);
  11.     if (variant == RRVariant::FastOrMsgSend) {
  12.         // 这些检查只对 objc_retain()
  13.         // 他们在这里是为了避免我们重新装载isa。
  14.         if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) {
  15.             ClearExclusive(&isa.bits);
  16.             if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
  17.                 return swiftRetain.load(memory_order_relaxed)((id)this);
  18.             }
  19.             return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(retain));
  20.         }
  21.     }
  22.     if (slowpath(!oldisa.nonpointer)) {
  23.         // 一个类永远是一个类,所以我们可以执行一次检查
  24.         // 在CAS环外
  25.         if (oldisa.getDecodedClass(false)->isMetaClass()) {
  26.             ClearExclusive(&isa.bits);
  27.             return (id)this;
  28.         }
  29.     }
  30.     //重点
  31.     do {
  32.     // 初始化 transcribeToSideTable 为 false,表示不需要将引用计数转移到 side table
  33.     //这里是先设置默认情况下的transcribeToSideTable
  34.     transcribeToSideTable = false;
  35.     // 将 oldisa 的值赋给 newisa,用于后续的引用计数增加操作
  36.     newisa = oldisa;
  37.    
  38.     // 检查 newisa 是否为 nonpointer isa
  39.     //nonpointer isa 是一种优化技术,用于将额外的信息编码到 isa 指针中。它和taggedPointer是不一样的
  40.     if (slowpath(!newisa.nonpointer)) {
  41.         // 如果 newisa 不是 nonpointer isa,清除 isa 的原子锁
  42.         ClearExclusive(&isa().bits);
  43.         // 如果 tryRetain 为 true,尝试 sidetable 的 tryRetain 方法
  44.         if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
  45.         // 否则调用 sidetable 的 retain 方法
  46.         else return sidetable_retain(sideTableLocked);
  47.     }
  48.    
  49.     // 不检查 newisa.fast_rr,因为我们已经调用了 RR 覆盖
  50.     // 检查对象是否正在被 deallocating
  51.     if (slowpath(newisa.isDeallocating())) {
  52.         // 如果对象正在被 deallocating,清除 isa 的原子锁
  53.         ClearExclusive(&isa().bits);
  54.         // 如果 sideTableLocked 为 true,解锁 side table
  55.         if (sideTableLocked) {
  56.             ASSERT(variant == RRVariant::Full);
  57.             sidetable_unlock();
  58.         }
  59.         // 如果 tryRetain 为 true,返回 nil,表示无法增加引用计数;否则返回对象本身
  60.         if (slowpath(tryRetain)) {
  61.             return nil;
  62.         } else {
  63.             return (id)this;
  64.         }
  65.     }
  66.    
  67.     uintptr_t carry;
  68.     // 增加引用计数,即对 newisa.bits 中的引用计数位进行加一操作
  69.     newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++
  70.    
  71.     // 检查引用计数是否溢出
  72.     if (slowpath(carry)) {
  73.         // 如果引用计数溢出,且 variant 不为 Full,清除 isa 的原子锁并调用 rootRetain_overflow
  74.         if (variant != RRVariant::Full) {
  75.             ClearExclusive(&isa().bits);
  76.             return rootRetain_overflow(tryRetain);
  77.         }
  78.         // 保留一半的引用计数在 inline,并准备将另一半复制到 side table
  79.         if (!tryRetain && !sideTableLocked) sidetable_lock();
  80.         sideTableLocked = true;
  81.         transcribeToSideTable = true;
  82.         newisa.extra_rc = RC_HALF;
  83.         newisa.has_sidetable_rc = true;
  84.     }
  85. // 尝试将 newisa 存储到 isa.bits 中,如果存储失败,则循环重新尝试
  86. } while (slowpath(!StoreExclusive(&isa().bits, &oldisa.bits, newisa.bits)));
  87.     if (variant == RRVariant::Full) {
  88.         if (slowpath(transcribeToSideTable)) {
  89.             // 把剩下的一半放到 side table.
  90.             sidetable_addExtraRC_nolock(RC_HALF);
  91.         }
  92.         if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
  93.     } else {
  94.         ASSERT(!transcribeToSideTable);
  95.         ASSERT(!sideTableLocked);
  96.     }
  97.     return (id)this;
  98. }
复制代码
这段代码的逻辑是:起首初始化并赋值变量,然后进入循环,查抄 newisa 是否为 nonpointer isa,如果不是,则清除 isa 的原子锁。如果 tryRetain 为真,则实行调用 sidetable_tryRetain 增加引用计数,否则调用 sidetable_retain 增加引用计数。如果对象正在被释放,则清除 isa 的原子锁,并根据条件返回 nil 或对象。接着,实行增加引用计数并查抄是否溢出,如果溢出,则将部分引用计数转移到 side table 并设置相干标记。循环结束时,查抄并处理 side table 的引用计数操作。
我们再看看sidetable_tryRetain方法:
  1. bool
  2. objc_object::sidetable_tryRetain()
  3. {
  4. #if SUPPORT_NONPOINTER_ISA
  5. //确保对象的 isa 不是 nonpointer isa(如果支持 nonpointer isa)
  6.     ASSERT(!isa().nonpointer);
  7. #endif
  8.     //从全局的sideTable中获取当前对象的sideTable
  9.     SideTable& table = SideTables()[this];
  10.     // NO SPINLOCK HERE
  11.     // _objc_rootTryRetain() is called exclusively by _objc_loadWeak(),
  12.     // which already acquired the lock on our behalf.
  13.     // fixme can't do this efficiently with os_lock_handoff_s
  14.     // if (table.slock == 0) {
  15.     //     _objc_fatal("Do not call -_tryRetain.");
  16.     // }
  17.     bool result = true;
  18.     //在 SideTable 的 refcnts 中尝试插入当前对象。如果插入成功,则表示该对象以前没有引用计数记录,新建的条目引用计数为 1。
  19.     auto it = table.refcnts.try_emplace(this, SIDE_TABLE_RC_ONE);
  20.     //获取并引用映射中元素的值部分
  21.     auto &refcnt = it.first->second;
  22.     //如果插入了新条目(即条目不存在),什么也不做,因为条目已经初始化为 SIDE_TABLE_RC_ONE。
  23.     if (it.second) {
  24.         //如果条目已经存在,检查是否有 SIDE_TABLE_DEALLOCATING 标志。如果有,设置 result 为 false,表示无法增加引用计数。
  25.     } else if (refcnt & SIDE_TABLE_DEALLOCATING) {
  26.         result = false;
  27.         //如果条目已经存在并且没有 SIDE_TABLE_DEALLOCATING 标志,再检查是否有 SIDE_TABLE_RC_PINNED 标志。如果没有,增加引用计数 SIDE_TABLE_RC_ONE。
  28.     } else if (! (refcnt & SIDE_TABLE_RC_PINNED)) {
  29.         refcnt += SIDE_TABLE_RC_ONE;
  30.     }
  31.    
  32.     return result;
  33. }
复制代码
这段代码用于实行增加对象的引用计数。
起首确保对象的 isa 不是 nonpointer isa,然后从全局的 SideTables 中获取当前对象的 SideTable。
在 SideTable 的 refcnts 中实行插入当前对象。如果插入成功,则表示该对象从前没有引用计数记录,新建的条目引用计数为 1。如果对象已经存在于 SideTable 中,查抄引用计数标记:
如果对象正在被释放(DEALLOCATING),返回 false,表示增加引用计数失败。
如果引用计数没有被固定(没有 SIDE_TABLE_RC_PINNED 标记),增加引用计数。
retain总体流程大概如下图:

release

源码:
  1. // Equivalent to calling [this release], with shortcuts if there is no override
  2. inline void
  3. objc_object::release()
  4. {
  5.     ASSERT(!isTaggedPointer());
  6.     rootRelease(true, RRVariant::FastOrMsgSend);
  7. }
  8. ALWAYS_INLINE bool
  9. objc_object::rootRelease()
  10. {
  11.     return rootRelease(true, RRVariant::Fast);
  12. }
  13. inline void
  14. objc_object::release()
  15. {
  16.     ASSERT(!isTaggedPointer());
  17.     if (fastpath(!ISA()->hasCustomRR())) {
  18.         // Standard RR of a class is a no-op.
  19.         if (!ISA()->isMetaClass())
  20.             sidetable_release();
  21.         return;
  22.     }
  23.     ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(release));
  24. }
复制代码
  1. ALWAYS_INLINE bool
  2. objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)
  3. {
  4.     // 如果是标记指针,直接返回 false
  5.     if (slowpath(isTaggedPointer())) return false;
  6.     bool sideTableLocked = false; // 用于标记侧表是否被锁定
  7.     isa_t newisa, oldisa; // 定义 isa_t 类型的变量 newisa 和 oldisa
  8.     // 加载 isa 值到 oldisa 中
  9.     oldisa = LoadExclusive(&isa().bits);
  10.     // 如果引用计数变种是 FastOrMsgSend
  11.     if (variant == RRVariant::FastOrMsgSend) {
  12.         // 这些检查仅对 objc_release() 有意义
  13.         // 它们在这里是为了避免重新加载 isa
  14.         if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) {
  15.             ClearExclusive(&isa().bits); // 清除独占标记
  16.             if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
  17.                 // 如果可以调用 Swift 的引用计数方法
  18.                 swiftRelease.load(memory_order_relaxed)((id)this);
  19.                 return true;
  20.             }
  21.             // 调用 objc_msgSend 的 release 方法
  22.             ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(release));
  23.             return true;
  24.         }
  25.     }
  26.     // 检查 isa 是否为指针形式
  27.     if (slowpath(!oldisa.nonpointer)) {
  28.         // 一个类永远是一个类,所以我们可以在 CAS 循环外进行此检查
  29.         if (oldisa.getDecodedClass(false)->isMetaClass()) {
  30.             ClearExclusive(&isa().bits); // 清除独占标记
  31.             return false;
  32.         }
  33.     }
  34. #if !ISA_HAS_INLINE_RC
  35.     // 如果不支持内联引用计数,使用侧表
  36.     ClearExclusive(&isa().bits); // 清除独占标记
  37.     return sidetable_release(sideTableLocked, performDealloc);
  38. #else
  39. retry:
  40.     do {
  41.         newisa = oldisa; // 将 oldisa 赋值给 newisa
  42.         if (slowpath(!newisa.nonpointer)) {
  43.             ClearExclusive(&isa().bits); // 清除独占标记
  44.             return sidetable_release(sideTableLocked, performDealloc);
  45.         }
  46.         if (slowpath(newisa.isDeallocating())) {
  47.             ClearExclusive(&isa().bits); // 清除独占标记
  48.             if (sideTableLocked) {
  49.                 ASSERT(variant == RRVariant::Full);
  50.                 sidetable_unlock(); // 解锁侧表
  51.             }
  52.             return false;
  53.         }
  54.         // 不检查 newisa.fast_rr; 我们已经调用了任何 RR 重载
  55.         uintptr_t carry;
  56.         newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry); // extra_rc--
  57.         if (slowpath(carry)) {
  58.             // 不清除独占标记
  59.             goto underflow;
  60.         }
  61.     } while (slowpath(!StoreReleaseExclusive(&isa().bits, &oldisa.bits, newisa.bits)));
  62.     if (slowpath(newisa.isDeallocating()))
  63.         goto deallocate;
  64.     if (variant == RRVariant::Full) {
  65.         if (slowpath(sideTableLocked)) sidetable_unlock();
  66.     } else {
  67.         ASSERT(!sideTableLocked);
  68.     }
  69.     return false;
  70. underflow:
  71.     // newisa.extra_rc-- 下溢:从侧表借用或析构
  72.     // 放弃 newisa 以撤销递减
  73.     newisa = oldisa;
  74.     if (slowpath(newisa.has_sidetable_rc)) {
  75.         if (variant != RRVariant::Full) {
  76.             ClearExclusive(&isa().bits); // 清除独占标记
  77.             return rootRelease_underflow(performDealloc);
  78.         }
  79.         // 将引用计数从侧表转移到内联存储
  80.         if (!sideTableLocked) {
  81.             ClearExclusive(&isa().bits); // 清除独占标记
  82.             sidetable_lock(); // 锁定侧表
  83.             sideTableLocked = true;
  84.             // 需要重新开始以避免与指针非指针转换的竞争
  85.             oldisa = LoadExclusive(&isa().bits);
  86.             goto retry;
  87.         }
  88.         // 尝试从侧表中删除一些引用计数
  89.         auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
  90.         bool emptySideTable = borrow.remaining == 0; // 如果侧表中没有引用计数,将清空侧表
  91.         if (borrow.borrowed > 0) {
  92.             // 侧表引用计数减少
  93.             // 尝试将它们添加到内联计数
  94.             bool didTransitionToDeallocating = false;
  95.             newisa.extra_rc = borrow.borrowed - 1; // 重新执行原始递减
  96.             newisa.has_sidetable_rc = !emptySideTable;
  97.             bool stored = StoreReleaseExclusive(&isa().bits, &oldisa.bits, newisa.bits);
  98.             if (!stored && oldisa.nonpointer) {
  99.                 // 内联更新失败
  100.                 // 立即重试。这可以防止在 LL/SC 架构上发生活锁,
  101.                 // 因为侧表访问本身可能会丢失预留
  102.                 uintptr_t overflow;
  103.                 newisa.bits =
  104.                     addc(oldisa.bits, RC_ONE * (borrow.borrowed-1), 0, &overflow);
  105.                 newisa.has_sidetable_rc = !emptySideTable;
  106.                 if (!overflow) {
  107.                     stored = StoreReleaseExclusive(&isa().bits, &oldisa.bits, newisa.bits);
  108.                     if (stored) {
  109.                         didTransitionToDeallocating = newisa.isDeallocating();
  110.                     }
  111.                 }
  112.             }
  113.             if (!stored) {
  114.                 // 内联更新失败
  115.                 // 将保留重新放回侧表
  116.                 ClearExclusive(&isa().bits);
  117.                 sidetable_addExtraRC_nolock(borrow.borrowed);
  118.                 oldisa = LoadExclusive(&isa().bits);
  119.                 goto retry;
  120.             }
  121.             // 从侧表借用后的递减成功
  122.             if (emptySideTable)
  123.                 sidetable_clearExtraRC_nolock();
  124.             if (!didTransitionToDeallocating) {
  125.                 if (slowpath(sideTableLocked)) sidetable_unlock();
  126.                 return false;
  127.             }
  128.         }
  129.         else {
  130.             // 侧表最终为空,进入析构路径
  131.         }
  132.     }
  133. deallocate:
  134.     // 真的要析构了
  135.     ASSERT(newisa.isDeallocating());
  136.     ASSERT(isa().isDeallocating());
  137.     if (slowpath(sideTableLocked)) sidetable_unlock();
  138.     __c11_atomic_thread_fence(__ATOMIC_ACQUIRE);
  139.     if (performDealloc) {
  140.         this->performDealloc();
  141.     }
  142.     return true;
  143. #endif // ISA_HAS_INLINE_RC
  144. }
复制代码
  1. uintptr_t
  2. objc_object::sidetable_release(bool locked, bool performDealloc)
  3. {
  4. #if SUPPORT_NONPOINTER_ISA
  5.     ASSERT(!isa().nonpointer);
  6. #endif
  7.     // 获取当前对象的侧表
  8.     SideTable& table = SideTables()[this];
  9.     bool do_dealloc = false; // 标记是否需要析构
  10.     // 如果未锁定侧表,先锁定它
  11.     if (!locked) table.lock();
  12.    
  13.     // 尝试在侧表的引用计数字典中插入一个新条目
  14.     // 如果该对象不在侧表中,插入 {this, SIDE_TABLE_DEALLOCATING}
  15.     auto it = table.refcnts.try_emplace(this, SIDE_TABLE_DEALLOCATING);
  16.     auto &refcnt = it.first->second; // 获取引用计数
  17.   //判断是否进行了插入操作
  18.     if (it.second) {
  19.         // 如果对象之前不在侧表中,表示这是第一次插入
  20.         // 设置 do_dealloc 为 true,表示需要析构
  21.         do_dealloc = true;
  22.     } else if (refcnt < SIDE_TABLE_DEALLOCATING) {
  23.         // 如果引用计数小于 SIDE_TABLE_DEALLOCATING
  24.         // 表示引用计数为负数,可能设置了 SIDE_TABLE_WEAKLY_REFERENCED
  25.         // 设置 do_dealloc 为 true,并将引用计数标记为 SIDE_TABLE_DEALLOCATING
  26.         do_dealloc = true;
  27.         refcnt |= SIDE_TABLE_DEALLOCATING;
  28.     } else if (! (refcnt & SIDE_TABLE_RC_PINNED)) {
  29.         // 如果引用计数未固定(未设置 SIDE_TABLE_RC_PINNED)
  30.         // 将引用计数减一
  31.         refcnt -= SIDE_TABLE_RC_ONE;
  32.     }
  33.     // 解锁侧表
  34.     table.unlock();
  35.     // 如果需要析构且 performDealloc 为真,执行析构操作
  36.     if (do_dealloc && performDealloc) {
  37.         this->performDealloc();
  38.     }
  39.     // 返回是否需要析构
  40.     return do_dealloc;
  41. }
复制代码
实现了 objc_object 的引用计数淘汰操作,并根据引用计数的变革决定是否需要进行对象的析构。

dealloc

dealloc用于在对象的引用计数为0的时候,释放该对象,那么在底层,它是怎样实现的呢.
  1. inline void objc_object::rootDealloc()
  2. {
  3.     // 如果对象是 tagged pointer(标记指针),直接返回
  4.     if (isTaggedPointer()) return;  // fixme necessary?
  5.    
  6. #if !ISA_HAS_INLINE_RC
  7.     // 如果没有内联引用计数,直接调用 object_dispose 释放对象
  8.     object_dispose((id)this);
  9. #else
  10.     // 如果有内联引用计数,并且满足以下所有条件,则直接释放内存
  11.     if (fastpath(isa().nonpointer &&               // 非指针 ISA
  12.                  !isa().weakly_referenced &&       // 没有弱引用
  13.                  !isa().has_assoc &&               // 没有关联对象
  14. #if ISA_HAS_CXX_DTOR_BIT
  15.                  !isa().has_cxx_dtor &&            // 没有 C++ 析构函数
  16. #else
  17.                  !isa().getClass(false)->hasCxxDtor() && // 没有 C++ 析构函数
  18. #endif
  19.                  !isa().has_sidetable_rc))         // 没有使用 side table 引用计数
  20.     {
  21.         // 确认没有 side table 存在
  22.         assert(!sidetable_present());
  23.         // 直接释放内存
  24.         free(this);
  25.     }
  26.     else {
  27.         // 否则,调用 object_dispose 释放对象
  28.         object_dispose((id)this);
  29.     }
  30. #endif // ISA_HAS_INLINE_RC
  31. }
复制代码
用于销毁和释放对象:
  1. id object_dispose(id obj)
  2. {
  3.     // 如果 obj 是空指针,则直接返回 nil
  4.     if (!obj) return nil;
  5.     // 调用 objc_destructInstance 函数,销毁对象实例的内容
  6.     objc_destructInstance(obj);
  7.    
  8.     // 释放对象所占用的内存
  9.     free(obj);
  10.     // 返回 nil,表示对象已被销毁
  11.     return nil;
  12. }
复制代码
  1. objc_object::clearDeallocating()
  2. {
  3.     if (slowpath(!isa.nonpointer)) {
  4.         // Slow path for raw pointer isa.
  5.         // 如果要释放的对象没有采用了优化过的isa引用计数
  6.         sidetable_clearDeallocating();
  7.     }
  8.     else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
  9.         // Slow path for non-pointer isa with weak refs and/or side table data.
  10.         // 如果要释放的对象采用了优化过的isa引用计数,并且有弱引用或者使用了sideTable的辅助引用计数
  11.         clearDeallocating_slow();
  12.    }
  13.    //确保 side table 中没有该对象的引用计数记录。
  14.     assert(!sidetable_present());
  15. }
复制代码
上面这段代码根据是否采用了优化过的isa做引用计数分为两种:

  • 要释放的对象没有采用优化过的isa引用计数:会调用sidetable_clearDeallocating() 函数在 side table 中整理对象的引用计数。
  1. void
  2. objc_object::sidetable_clearDeallocating()
  3. {
  4.     // 在全局的SideTables中,以this指针(要释放的对象)为key,找到对应的SideTable
  5.     SideTable& table = SideTables()[this];
  6.     // clear any weak table items
  7.     // clear extra retain count and deallocating bit
  8.     // (fixme warn or abort if extra retain count == 0 ?)
  9.     table.lock();
  10.     //在散列表SideTable中找到对应的引用计数表RefcountMap,拿到要释放的对象的引用计数
  11.     RefcountMap::iterator it = table.refcnts.find(this);
  12.     if (it != table.refcnts.end()) {
  13.         //如果要释放的对象被弱引用了,通过weak_clear_no_lock函数将指向该对象的弱引用指针置为nil
  14.         if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {
  15.             weak_clear_no_lock(&table.weak_table, (id)this);
  16.         }
  17.         //从引用计数表中擦除该对象的引用计数
  18.         table.refcnts.erase(it);
  19.     }
  20.     table.unlock();
  21. }
复制代码
先找到对应的 SideTable,并对其加锁。
查找引用计数表 refcnts 中该对象的引用计数。
如果找到该对象的引用计数且被弱引用,则整理弱引用。
末了擦除该对象的引用计数,并解锁 SideTable。

  • 如果该对象采用了优化过的isa引用计数而且该对象有弱引用或者使用了sideTable的辅助引用计数,就会调用clearDeallocating_slow()函数处理引用计数
  1. NEVER_INLINE void
  2. objc_object::clearDeallocating_slow()
  3. {
  4.     assert(isa.nonpointer  &&  (isa.weakly_referenced || isa.has_sidetable_rc));
  5.     // 在全局的SideTables中,以this指针(要释放的对象)为key,找到对应的SideTable
  6.     SideTable& table = SideTables()[this];
  7.     table.lock();
  8.     if (isa.weakly_referenced) {
  9.         //要释放的对象被弱引用了,通过weak_clear_no_lock函数将指向该对象的弱引用指针置为nil
  10.         weak_clear_no_lock(&table.weak_table, (id)this);
  11.     }
  12.     //使用了sideTable的辅助引用计数,直接在SideTable中擦除该对象的引用计数
  13.     if (isa.has_sidetable_rc) {
  14.         table.refcnts.erase(this);
  15.     }
  16.     table.unlock();
  17. }
复制代码
找到对应的 SideTable,并对其加锁。
如果对象被弱引用,整理弱引用。
如果对象使用了 side table 的引用计数,擦除该对象的引用计数。
末了解锁 SideTable。
以上两种情况都涉及weak_clear_no_lock函数, 它的作用就是将被弱引用对象的弱引用指针置为nil.
dealloc的流程:如果对象是 tagged pointer,则直接返回。如果没有内联引用计数,调用 object_dispose 释放对象;如果有内联引用计数,而且对象满意非指针 ISA、没有弱引用、没有关联对象、没有 C++ 析构函数以及没有使用 side table 引用计数等条件,则直接释放内存。否则,调用 object_dispose 进行标准的对象销毁和内存释放。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表