iOS - 引用计数(ARC)

1. 基本数据结构

objectivec 复制代码
// 对象结构
struct objc_object {
    isa_t isa;  // isa 指针,包含引用计数信息
};

// isa 的位域结构
union isa_t {
    uintptr_t bits;
    struct {
        uintptr_t nonpointer        : 1;  // 是否启用优化的 isa 指针
        uintptr_t has_assoc         : 1;  // 是否有关联对象
        uintptr_t has_cxx_dtor      : 1;  // 是否有 C++ 析构函数
        uintptr_t shiftcls          : 33; // 类的指针
        uintptr_t magic             : 6;  // 用于调试
        uintptr_t weakly_referenced : 1;  // 是否有弱引用
        uintptr_t deallocating      : 1;  // 是否正在释放
        uintptr_t has_sidetable_rc  : 1;  // 引用计数是否在 SideTable 中
        uintptr_t extra_rc          : 19; // 额外的引用计数值
    };
}

2. 引用计数存储位置

2.1 isa 优化

objectivec 复制代码
inline bool 
objc_object::hasNonpointerIsa() {
    return isa.nonpointer;  // 判断是否使用优化的 isa
}

// 引用计数存储在 isa 的情况
if (isa.nonpointer) {
    // 引用计数存储在 isa.extra_rc 中
    // 最多可存储 2^19 - 1 个引用
}

2.2 SideTable 存储

objectivec 复制代码
struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts;  // 引用计数哈希表
    weak_table_t weak_table;  // 弱引用表
};

// 当 isa 中的引用计数溢出时
if (isa.has_sidetable_rc) {
    // 引用计数存储在 SideTable 的 refcnts 中
}

3. 引用计数操作

3.1 retain 操作

objectivec 复制代码
id objc_retain(id obj) {
    if (!obj) return obj;
    if (obj->isTaggedPointer()) return obj;
    return obj->retain();
}

inline id 
objc_object::retain() {
    if (isTaggedPointer()) return this;
    
    if (fastpath(!ISA()->hasCustomRR())) {
        if (fastpath(isa.hasNonpointerIsa())) {
            addExtraRC_nolock();
        } else {
            sidetable_retain();
        }
    }
    return this;
}

3.2 release 操作

objectivec 复制代码
void objc_release(id obj) {
    if (!obj) return;
    if (obj->isTaggedPointer()) return;
    obj->release();
}

inline bool 
objc_object::release() {
    if (isTaggedPointer()) return false;
    
    if (fastpath(!ISA()->hasCustomRR())) {
        if (fastpath(isa.hasNonpointerIsa())) {
            return sidetable_release(true);
        }
        return sidetable_release(false);
    }
    return false;
}

4. 引用计数溢出处理

objectivec 复制代码
void objc_object::sidetable_addExtraRC_nolock(size_t delta_rc) {
    // 当 isa.extra_rc 即将溢出时
    if (isa.extra_rc + delta_rc > RC_MASK) {
        // 将引用计数迁移到 SideTable
        isa.has_sidetable_rc = true;
        auto &table = SideTables()[this];
        size_t& refcnt = table.refcnts[this];
        refcnt += delta_rc;
    } else {
        // 继续使用 isa 存储
        isa.extra_rc += delta_rc;
    }
}

5. 弱引用处理

5.1 弱引用表结构

objectivec 复制代码
struct weak_table_t {
    weak_entry_t *weak_entries;  // 弱引用数组
    size_t    num_entries;       // 条目数
    uintptr_t mask;             // 容量掩码
    uintptr_t max_hash_displacement;  // 最大哈希偏移
};

5.2 弱引用操作

objectivec 复制代码
id objc_loadWeakRetained(id *location) {
    id obj = *location;
    if (!obj) return nil;
    if (obj->isTaggedPointer()) return obj;
    return obj->rootRetain();
}

void objc_storeWeak(id *location, id obj) {
    _objc_weak_store(location, obj);
}

6. 自动释放池相关

objectivec 复制代码
void *objc_autoreleasePoolPush(void) {
    return AutoreleasePoolPage::push();
}

void objc_autoreleasePoolPop(void *ctxt) {
    AutoreleasePoolPage::pop(ctxt);
}

id objc_autorelease(id obj) {
    if (!obj) return obj;
    if (obj->isTaggedPointer()) return obj;
    return obj->autorelease();
}

7. 优化机制

7.1 Tagged Pointer

objectivec 复制代码
bool isTaggedPointer() {
    return ((uintptr_t)this & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}

// Tagged Pointer 对象不参与引用计数
if (obj->isTaggedPointer()) {
    return obj;  // 直接返回,不进行引用计数操作
}

7.2 散列表优化

objectivec 复制代码
// SideTable 的哈希表实现
struct RefcountMap : public objc::DenseMap<DisguisedPtr<objc_object>,size_t,true> {
    // 使用 DenseMap 提高查找效率
};

8. 内存管理策略

8.1 dealloc 流程

objectivec 复制代码
inline void 
objc_object::rootDealloc() {
    if (isTaggedPointer()) return;
    
    if (fastpath(isa.hasNonpointerIsa())) {
        // 快速释放路径
        if (fastpath(!isa.weakly_referenced && !isa.has_assoc)) {
            free(this);
            return;
        }
    }
    object_dispose((id)this);
}

8.2 引用计数检查

objectivec 复制代码
bool objc_object::rootTryRetain() {
    if (isTaggedPointer()) return true;
    
    if (fastpath(!ISA()->hasCustomRR())) {
        if (fastpath(isa.hasNonpointerIsa())) {
            // 尝试增加引用计数
            return sidetable_tryRetain();
        }
    }
    return false;
}

这个引用计数系统的设计考虑了:

  1. 性能优化(isa 优化、Tagged Pointer)
  2. 内存效率(分散存储策略)
  3. 线程安全(自旋锁、原子操作)
  4. 扩展性(支持自定义引用计数)
相关推荐
Anhty20 小时前
2026最新免费手机音频处理工具 !!
android·功能测试·ios·智能手机·音视频
2501_915909061 天前
iOS应用从开发到上架App Store的完整发布流程与步骤指南
android·ios·小程序·https·uni-app·webview
初雪云1 天前
UniApp 云打包拿到 IPA 后,真正的发布工作才刚开始
ios·自动化·编辑器·产品经理·iphone
Lancker1 天前
没有 Mac 也能上架 iOS:GitHub Actions 全自动构建 + 签名 + TestFlight 送审实录
macos·ios·github
茶底世界之下1 天前
晚霞要多暖?用 Awaking 只改色温做一次取舍
ios
酒神dnspup1 天前
多地区网站可用性监控怎么做?DNSPup 从基线到告警的完整实战
运维·ios·云计算·iphone·dns·网络监控
福兮说2 天前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic
fei_sun2 天前
RIB、FIB、MAC 、ARP 表
服务器·网络·macos
茶底世界之下2 天前
时间线效果层,为什么不能只复用一个处理器?
ios·swift
Highcharts.js2 天前
如何在macOS桌面应用集成Highcharts
macos·highcharts·前端可视化·交互图表