iOS - 弱引用表(Weak Reference Table)

1. 基本数据结构

objectivec 复制代码
// 弱引用表的基本结构
struct weak_table_t {
    weak_entry_t *weak_entries;      // 保存所有的弱引用对象
    size_t    num_entries;           // 当前存储的弱引用数量
    uintptr_t mask;                  // 哈希表大小掩码
    uintptr_t max_hash_displacement; // 最大哈希偏移值
};

// 单个对象的弱引用信息
struct weak_entry_t {
    DisguisedPtr<objc_object> referent;  // 被引用的对象
    union {
        struct {
            weak_referrer_t *referrers;        // 动态数组
            uintptr_t        out_of_line : 1;  // 是否使用动态数组
            uintptr_t        num_refs : PTR_MINUS_1;  // 引用计数
            uintptr_t        mask;             // 容量掩码
            uintptr_t        max_hash_displacement;
        };
        struct {
            // 内联存储,用于优化少量弱引用的情况
            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
        };
    };
};

2. 核心操作

2.1 添加弱引用

objectivec 复制代码
id weak_register_no_lock(weak_table_t *weak_table, id referent, 
                        id *referrer, bool crashIfDeallocating) {
    // 1. 查找或创建 entry
    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    if (entry == nil) {
        entry = new_entry_for_referent(referent, referrer);
        weak_entry_insert(weak_table, entry);
    }
    
    // 2. 添加弱引用
    append_referrer(entry, referrer);
    
    return referent;
}

2.2 移除弱引用

objectivec 复制代码
void weak_unregister_no_lock(weak_table_t *weak_table, 
                            id referent, id *referrer) {
    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    if (entry == nil) return;
    
    // 移除引用
    remove_referrer(entry, referrer);
    
    // 如果 entry 为空,则移除
    if (entry->out_of_line && entry->num_refs == 0) {
        weak_entry_remove(weak_table, entry);
    }
}

3. 存储优化

3.1 内联存储

objectivec 复制代码
#define WEAK_INLINE_COUNT 4

struct weak_entry_t {
    union {
        // 当弱引用数量少时,使用内联数组
        struct {
            weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
        };
        // 当弱引用数量多时,使用动态数组
        struct {
            weak_referrer_t *referrers;
            uintptr_t out_of_line : 1;
        };
    };
};

3.2 动态扩展

objectivec 复制代码
static void grow_refs_and_insert(weak_entry_t *entry, 
                                objc_object **new_referrer) {
    assert(entry->out_of_line());
    
    size_t old_size = TABLE_SIZE(entry);
    size_t new_size = old_size ? old_size * 2 : 8;
    
    // 分配新空间
    weak_referrer_t *new_refs = (weak_referrer_t *)
        calloc(new_size, sizeof(weak_referrer_t));
    
    // 迁移数据
    for (size_t i = 0; i < old_size; i++) {
        weak_referrer_t oldref = entry->referrers[i];
        if (oldref) {
            weak_referrer_t *new_ref = new_refs + hash_pointer(oldref);
            *new_ref = oldref;
        }
    }
}

4. 线程安全

4.1 锁保护

objectivec 复制代码
struct SideTable {
    spinlock_t slock;      // 自旋锁
    RefcountMap refcnts;
    weak_table_t weak_table;
    
    void lock() { slock.lock(); }
    void unlock() { slock.unlock(); }
};

// 使用示例
void weak_register_no_lock(weak_table_t *weak_table, id referent) {
    SideTable& table = SideTables()[referent];
    table.lock();
    // 操作 weak_table
    table.unlock();
}

4.2 原子操作

objectivec 复制代码
bool weak_entry_insert(weak_table_t *weak_table, weak_entry_t *new_entry) {
    return OSAtomicCompareAndSwapPtr(nil, new_entry, 
           (void * volatile *)&weak_table->weak_entries);
}

5. 清理机制

5.1 对象释放时的清理

objectivec 复制代码
void weak_clear_no_lock(weak_table_t *weak_table, id referent) {
    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    if (entry == nil) return;
    
    // 将所有弱引用置为 nil
    weak_referrer_t *referrers = entry->referrers;
    size_t count = entry->num_refs;
    
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            *referrer = nil;
        }
    }
    
    // 移除 entry
    weak_entry_remove(weak_table, entry);
}

5.2 表格清理

objectivec 复制代码
void weak_compact_maybe(weak_table_t *weak_table) {
    size_t old_size = TABLE_SIZE(weak_table);
    
    // 当表使用率低于 1/4 时进行收缩
    if (weak_table->num_entries < old_size / 4) {
        weak_resize(weak_table, old_size / 2);
    }
}

6. 性能优化

6.1 哈希优化

objectivec 复制代码
static inline uintptr_t hash_pointer(objc_object **p) {
    return ((uintptr_t)p) >> 3;  // 去除对齐位
}

static inline size_t index_for_pointer(uintptr_t ptr, size_t mask) {
    return ptr & mask;  // 快速取模
}

6.2 空间优化

objectivec 复制代码
// 使用内联数组优化小对象
if (entry->num_refs < WEAK_INLINE_COUNT) {
    // 使用内联存储
    entry->inline_referrers[entry->num_refs++] = referrer;
} else {
    // 转换为动态数组
    move_to_dynamic_storage(entry);
}

7. 注意事项

  1. 线程安全:
  • 所有操作都需要加锁保护
  • 使用原子操作进行关键更新
  • 内存管理:
  • 及时清理无用的 entry
  • 动态调整表大小避免内存浪费
  1. 性能考虑:
  • 使用内联存储优化小对象
  • 哈希算法优化查找效率
  • 正确性保证:
  • 对象释放时正确清理所有弱引用
  • 维护引用计数的准确性

这个设计在保证功能正确的同时,通过多种优化手段提供了良好的性能。

相关推荐
若水无华2 天前
fiddler 配置ios手机代理调试
ios·智能手机·fiddler
Aress"2 天前
【ios越狱包安装失败?uniapp导出ipa文件如何安装到苹果手机】苹果IOS直接安装IPA文件
ios·uni-app·ipa安装
Jouzzy2 天前
【iOS安全】Dopamine越狱 iPhone X iOS 16.6 (20G75) | 解决Jailbreak failed with error
安全·ios·iphone
瓜子三百克2 天前
采用sherpa-onnx 实现 ios语音唤起的调研
macos·ios·cocoa
左钦杨2 天前
IOS CSS3 right transformX 动画卡顿 回弹
前端·ios·css3
努力成为包租婆2 天前
SDK does not contain ‘libarclite‘ at the path
ios
安和昂3 天前
【iOS】Tagged Pointer
macos·ios·cocoa
I烟雨云渊T3 天前
iOS 阅后即焚功能的实现
macos·ios·cocoa
struggle20253 天前
适用于 iOS 的 开源Ultralytics YOLO:应用程序和 Swift 软件包,用于在您自己的 iOS 应用程序中运行 YOLO
yolo·ios·开源·app·swift
Unlimitedz3 天前
iOS视频编码详细步骤(视频编码器,基于 VideoToolbox,支持硬件编码 H264/H265)
ios·音视频