当前位置: 首页 > news >正文

iOS - 弱引用表(Weak Reference Table)

1. 基本数据结构

// 弱引用表的基本结构
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 添加弱引用

id weak_register_no_lock(weak_table_t *weak_table, id referent, id *referrer, bool crashIfDeallocating) {// 1. 查找或创建 entryweak_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 移除弱引用

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 内联存储

#define WEAK_INLINE_COUNT 4struct 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 动态扩展

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 锁保护

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_tabletable.unlock();
}

4.2 原子操作

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 对象释放时的清理

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;// 将所有弱引用置为 nilweak_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;}}// 移除 entryweak_entry_remove(weak_table, entry);
}

5.2 表格清理

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 哈希优化

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 空间优化

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

7. 注意事项

1. 线程安全:

  • 所有操作都需要加锁保护
  • 使用原子操作进行关键更新
  • 内存管理:
  • 及时清理无用的 entry
  • 动态调整表大小避免内存浪费

3. 性能考虑:

  • 使用内联存储优化小对象
  • 哈希算法优化查找效率
  • 正确性保证:
  • 对象释放时正确清理所有弱引用
  • 维护引用计数的准确性

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

http://www.lryc.cn/news/516469.html

相关文章:

  • C#语言的网络编程
  • 【操作系统】课程 4调度与死锁 同步测练 章节测验
  • 如何查看已经安装的python版本和相关路径信息
  • 设计模式-结构型-适配器模式
  • 鸿蒙操作系统(HarmonyOS)
  • 基于海思soc的智能产品开发(camera sensor的两种接口)
  • 解密LLM结构化输出:代码示例与原理分析
  • Go语言的数据类型
  • 复杂园区网基本分支的构建
  • 如何很快将文件转换成另外一种编码格式?编码?按指定编码格式编译?如何检测文件编码格式?Java .class文件编码和JVM运行期内存编码?
  • 《C++11》Lambda 匿名函数从入门到进阶 优缺点分析 示例
  • 连接Milvus
  • Linux——修改文件夹的所属用户组和用户
  • Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
  • 计算机Steam报错failedtoloadsteamui.dll怎么解决?DLL报错要怎么修复?
  • 如何开发一个简单的 dApp
  • TDengine 签约智园数字,助力化工园区智联未来
  • 《Python游戏编程入门》注-第9章8
  • js逆向实战(1)-- 某☁️音乐下载
  • AIA - APLIC之三(附APLIC处理流程图)
  • React Router 向路由组件传state参数浏览器回退历史页面显示效果问题
  • 线程池与并发工具:Java的分身管理器
  • 字玩FontPlayer开发笔记8 Tauri2文件系统
  • 头歌python实验:网络安全应用实践3-验证码识别
  • 客户案例:基于慧集通(DataLinkX)集成平台的金蝶云星空与HIS系统集成案例--凭证模板的配置(一)
  • 基于 Python 的大学教室资源管理系统的设计与实现
  • nginx-灰度发布策略(split_clients)
  • nginx正向代理从安装到使用一网打尽系列(二)使用
  • Bash Shell的操作环境
  • Python爬虫基础——认识网页结构(各种标签的使用)