【iOS】SideTable

文章目录

    • 前言
    • 1️⃣Side Table 的核心作用:扩展对象元数据存储
      • 1.1 传统对象的内存限制
      • 1.2 Side Table 的定位:集中式元数据仓库
    • 2️⃣Side Table 的底层结构与关联
      • 2.1 Side Table 与 isa 指针的关系
      • 2.2 Side Table 的存储结构
      • 2.3 SideTable 的工作流程
    • 3️⃣SideTable 的典型应用场景
      • 3.1 弱引用(`__weak`)的实现
      • 3.2 关联对象(Associated Objects)
      • 3.3 KVO(键值观察)的实现
      • 3.4 引用计数的优化存储
    • 4️⃣SideTable特点
    • 总结

前言

在 iOS/macOS 的内存管理中,Side Table(边表) 是苹果为优化对象元数据存储而设计的 辅助数据结构。它与对象的 isa 指针紧密关联,用于存储对象的额外信息(如引用计数、弱引用指针、关联对象等),解决了传统对象内存布局无法高效扩展的问题。它的设计与使用是OC运行时实现弱引用的基础,使得ARC能够正确地处理弱引用的生命周期。

1️⃣Side Table 的核心作用:扩展对象元数据存储

1.1 传统对象的内存限制

OC 对象的内存布局以 isa 指针为核心(指向类对象),但仅靠 isa 无法存储所有元数据:

  • 普通对象的 isa 指针仅指向类对象,无法直接存储引用计数、弱引用等动态信息。
  • 若为每个对象单独分配元数据内存,会导致内存碎片和性能下降。

1.2 Side Table 的定位:集中式元数据仓库

Side Table 是 全局共享的哈希表(或数组),为需要额外元数据的对象提供统一的存储空间。它的核心作用是:

  • 存储对象的扩展元数据(如引用计数、弱引用指针、关联对象键值对)。
  • 减少内存碎片:多个对象共享同一 Side Table 的存储空间,避免为每个对象单独分配内存。

2️⃣Side Table 的底层结构与关联

2.1 Side Table 与 isa 指针的关系

OC 对象的 isa 指针(Class 类型)在 64 位系统中被扩展为 uintptr_t 类型(无符号长整型),通过 位域(Bit Field) 存储额外信息:

  • 低 48 位:指向类对象或 Side Table 的地址(具体取决于对象类型)。
  • 高 16 位:存储标记位(如是否为 weak 对象、是否需要 Side Table 等)。
/*_arm64(对应ios移动端)*/ 
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD                                                     \uintptr_t nonpointer        : 1; /*是否使用非指针格式*/                                      \uintptr_t has_assoc         : 1; /*是否有关联对象*/                                      \uintptr_t has_cxx_dtor      : 1; /*是否有C++析构函数*/                                      \uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ /*存储类指针的核心字段(加密后)*/ \uintptr_t magic             : 6; /*​​验证指针合法性​​ 调试器将提取的 magic_value 与预定义的合法值(ISA_MAGIC_VALUE)比较*/                                      \uintptr_t weakly_referenced : 1;  /*是否为弱饮用*/                                     \uintptr_t unused            : 1;  /*保留位(数据结构或协议中预留的未使用位)*/                                     \uintptr_t has_sidetable_rc  : 1;  /*是否使用弱引用表*/                                     \uintptr_t extra_rc          : 19  /*内联引用计数(最大2^19-1)*/# elif __x86_64__ //__x86_64__(对应macos)(与上面一样)
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   define ISA_BITFIELD                                                        \uintptr_t nonpointer        : 1;                                         \uintptr_t has_assoc         : 1;                                         \uintptr_t has_cxx_dtor      : 1;                                         \uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \uintptr_t magic             : 6;                                         \uintptr_t weakly_referenced : 1;                                         \uintptr_t unused            : 1;                                         \uintptr_t has_sidetable_rc  : 1;                                         \uintptr_t extra_rc          : 8  /*(最大为2^8-1)*/

在上述isa的结构体代码中,extra_rchas_sidetable_rc,这两者共同记录引用计数器。

关键逻辑
当对象需要存储额外元数据时(如弱引用),isa 指针的高位会被标记为“需要 Side Table”,并通过低 48 位指向对应的 Side Table 条目。

2.2 Side Table 的存储结构

Side Table 的底层实现是一个 全局的哈希表(或数组),每个条目对应一个对象的内存地址,存储其扩展元数据。不同平台(iOS/macOS)的实现略有差异,但核心结构相似:

字段描述
refcount引用计数(用于 ARC 管理)。
weak_refs弱引用指针数组(存储指向该对象的弱引用变量地址)。
associated_objects关联对象键值对(存储通过 objc_setAssociatedObject 设置的关联数据)。
flags标记位(如是否被标记为待释放、是否为类对象等)。

在obj4-906中,sideTable部分的结构如下:

struct SideTable {spinlock_t slock;  //自旋锁RefcountMap refcnts;  //引用计数映射表weak_table_t weak_table;  //弱引用表SideTable() {memset(&weak_table, 0, sizeof(weak_table));} //SideTable():构造函数,使用memeset将weak_table初始化为0,确保弱引用表的初始状态安全。~SideTable() {_objc_fatal("Do not delete SideTable.");} //~SideTable():析构函数,调用 _objc_fatal("Do not delete SideTable.")防止手动释放。SideTable的生命周期由 Objective-C 运行时管理(如对象销毁时自动释放),禁止用户主动删除。void lock() { slock.lock(); }void unlock() { slock.unlock(); }//直接操作自旋锁 slock,用于保护对 refcnts和 weak_table的修改。void reset() { slock.reset(); }  //重置自旋锁状态(具体实现依赖 spinlock_t的底层逻辑,通常用于释放锁或重置为未锁定状态)。// Address-ordered lock discipline for a pair of side tables.template<HaveOld, HaveNew>static void lockTwo(SideTable *lock1, SideTable *lock2);template<HaveOld, HaveNew>static void unlockTwo(SideTable *lock1, SideTable *lock2);
};

slock是一个自旋锁:保证对 SideTable中数据(如引用计数、弱引用表)的线程安全访问。自旋锁适用于临界区较小的场景(引用计数修改通常很快),避免线程阻塞开销。
请添加图片描述
refcnts是引用计数映射表:存储当前对象的引用计数值。RefcountMap本质是一个轻量级的哈希表或键值对结构,键为对象的内存地址(或唯一标识),值为对应的引用计数值。
请添加图片描述

weak_table是弱引用表:存储所有指向当前对象的弱引用指针(__weak修饰的指针)。弱引用表的核心功能是:当对象被释放时,自动将所有弱引用置为 nil,避免野指针。

weak_table_t源码结构如下:

/*** The global weak references table. Stores object ids as keys,* and weak_entry_t structs as their values.*/
struct weak_table_t {weak_entry_t *weak_entries;  //弱引用条目数组:指向 weak_entry_t结构体的指针数组。每个 weak_entry_t对应一个指向当前对象的 __weak指针,存储弱引用的具体信息(如指针地址、对象状态等)size_t    num_entries;  //弱引用条目数量:记录当前 weak_table_t中有效弱引用条目的数量(即 weak_entries数组中实际使用的元素个数)uintptr_t mask;  //哈希掩码:用于计算弱引用的哈希索引,优化哈希表的存储和查找效率//弱引用的哈希值通常通过 hash ^ mask计算(hash是弱引用指针的哈希值),结果对齐到 weak_entries数组的大小。mask的值通常为数组大小减一(如数组大小为 2^n,则 mask = (1 << n) - 1),确保索引在数组范围内uintptr_t max_hash_displacement;  //最大哈希位移
};

关于weak_entry_t,,其源码在obj4_906中是这样的:

#define WEAK_INLINE_COUNT 4
#define REFERRERS_OUT_OF_LINE 2
struct weak_entry_t {DisguisedPtr<objc_object> referent;union {struct {weak_referrer_t *referrers;  // 外联弱引用指针数组(动态分配)uintptr_t        out_of_line_ness : 2;  // 标记为外联存储(固定为 1)uintptr_t        num_refs : PTR_MINUS_2;  // 弱引用数量(减去 2 位用于其他标记)uintptr_t        mask;  // 哈希掩码(用于快速查找)uintptr_t        max_hash_displacement;  // 最大哈希位移(解决哈希冲突)};struct {// out_of_line_ness field is low bits of inline_referrers[1]weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];};bool out_of_line() {return (out_of_line_ness == REFERRERS_OUT_OF_LINE);}weak_entry_t& operator=(const weak_entry_t& other) {memcpy(this, &other, sizeof(other));return *this;}weak_entry_t(objc_object *newReferent, objc_object **newReferrer): referent(newReferent){inline_referrers[0] = newReferrer;for (int i = 1; i < WEAK_INLINE_COUNT; i++) {inline_referrers[i] = nil;}}
};

2.3 SideTable 的工作流程

由上述源码,我们可以略微推断出sideTable的工作流程:

  1. 对象创建:当对象大小超过小对象阈值时,运行时为其分配 SideTable,并将引用计数初始化为 1(retainCount)。
  2. 引用计数修改:调用 retain/release时,运行时通过对象的 isa指针找到对应的 SideTable,加锁后修改 refcnts中的计数值。
  3. 弱引用注册:当对象被 __weak指针指向时,运行时将其弱引用指针注册到 SideTableweak_table中。
  4. 对象释放:当引用计数减至 0 时,运行时触发 dealloc,遍历 weak_table将所有弱引用置为 nil,然后释放 SideTable关联的资源(如 refcntsweak_table内存)。

3️⃣SideTable 的典型应用场景

3.1 弱引用(__weak)的实现

__weak 修饰的变量不会增加对象的引用计数,但需在对象释放时自动置空。Side Table 是其核心实现载体:

流程

  1. 当对象被 __weak 变量引用时,系统会在 Side Table 中为该对象创建条目。
  2. __weak 变量的值存储为 Side Table 条目的索引(而非直接存储对象地址)。
  3. 对象释放时,通过 Side Table 找到所有指向它的 __weak 变量,并将其置空。

3.2 关联对象(Associated Objects)

通过 objc_setAssociatedObjectobjc_getAssociatedObject 设置的关联对象,其数据实际存储在 Side Table 中:

示例

// 为 NSObject 实例添加关联对象(键为 "com.example.name")
NSString *name = @"张三";
objc_setAssociatedObject(obj, (__bridge const void *)(@"com.example.name"), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);// 从 Side Table 中读取关联对象
NSString *storedName = objc_getAssociatedObject(obj, (__bridge const void *)(@"com.example.name"));

底层逻辑
关联对象的键(如 @"com.example.name")和值会被存储在 Side Table 的 associated_objects 字段中,键通过哈希映射快速查找。

3.3 KVO(键值观察)的实现

KVO 的核心是 动态生成子类 并重写 setter 方法,但观察者列表(observers)的存储依赖 Side Table:

流程

  1. 当对对象属性添加 KVO 观察时,系统会生成一个该对象的子类(如 NSKVONotifying_Obj)。
  2. 子类的 isa 指针指向 Side Table 中的观察者列表条目。
  3. 属性值变化时,通过 Side Table 找到所有观察者并触发通知。

3.4 引用计数的优化存储

ARC 下,对象的引用计数(retainCount)不再直接存储在对象内存中,而是通过 Side Table 的 refcount 字段统一管理:

  • 引用计数增加(retain)时,更新 Side Table 中的 refcount
  • 引用计数减少(release)时,检查 refcount 是否为 0,若为 0 则触发对象释放。

4️⃣SideTable特点

  • 内存布局:紧凑高效

SideTable 的条目(Entry)在内存中是 连续存储 的,通过哈希表快速查找。每个条目的大小根据存储内容动态调整(如仅存储弱引用时,条目较小;存储关联对象时,条目较大)。

  • 线程安全:锁保护

Side Table 的读写需保证线程安全,苹果通过 自旋锁(Spin Lock)信号量(Semaphore) 实现:修改 Side Table(如添加/删除条目)时加锁;读取 Side Table(如获取弱引用列表)时加锁或使用无锁读取(CAS 操作)。

  • 版本演进:从 __objc_sideTableobjc_sideTable

早期 iOS 版本(如 iOS 9 前)使用 __objc_sideTable 结构体,存储方式为数组;iOS 10 后优化为哈希表(objc_sideTable),提升了查找效率。

总结

Side Table 是 iOS 内存管理的“元数据中心”,通过集中存储对象的扩展信息(引用计数、弱引用、关联对象等),解决了传统对象内存布局的局限性。它的存在让 OC 能够高效支持 ARC、弱引用、KVO 等高级特性,是苹果内存管理优化的关键技术之一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90534.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Spring Cloud Gateway 实战系列】高级篇:服务网格集成、安全增强与全链路压测

一、服务网格集成&#xff1a;Gateway与Istio的协同作战在微服务架构向服务网格演进的过程中&#xff0c;Spring Cloud Gateway可与Istio形成互补——Gateway负责南北向流量&#xff08;客户端到集群&#xff09;的入口管理&#xff0c;Istio负责东西向流量&#xff08;集群内服…

一文说清楚Hive

Hive作为Apache Hadoop生态的核心数据仓库工具&#xff0c;其设计初衷是为熟悉SQL的用户提供大规模数据离线处理能力。以下从底层计算框架、优点、场景、注意事项及实践案例五个维度展开说明。 一、Hive底层分布式计算框架对比 Hive本身不直接执行计算&#xff0c;而是将HQL转换…

SeaweedFS深度解析(三):裸金属单机和集群部署

#作者&#xff1a;闫乾苓 文章目录2.2.4 S3 Server&#xff08;兼容 Amazon S3 的接口&#xff09;2.2.5 Weed&#xff08;命令行工具&#xff09;3、裸金属单机和集群部署3.1 裸金属单机部署3.1.1安装 SeaweedFS3.1.2 以Master模式启动2.2.4 S3 Server&#xff08;兼容 Amazon…

相机ROI 参数

相机的 ROI&#xff08;Region of Interest&#xff0c;感兴趣区域&#xff09; 参数&#xff0c;是指通过设置图像传感器上 特定区域 作为有效成像区域&#xff0c;从而只采集该区域的图像数据&#xff0c;而忽略其他部分。这一功能常用于工业相机、科研相机、高速相机等场景&…

Vue基础(24)_VueCompinent构造函数、Vue实例对象与组件实例对象

分析上一节代码中的school组件&#xff1a;该组件是一个名为VueCompinent的构造函数。截取部分vue.js源码&#xff0c;分析Vue.extend&#xff1a;// 定义一个名为VueComponent的构造函数对象Sub&#xff0c;往Sub对象调用_init(options)方法&#xff0c;参数为配置项&#xff…

萤石云替代产品摄像头方案萤石云不支持TCP本地连接-东方仙盟

不断试错东方仙盟深耕科研测评&#xff0c;聚焦前沿领域&#xff0c;以严谨标准评估成果&#xff0c;追踪技术突破&#xff0c;在探索与验证中持续精进&#xff0c;为科研发展提供参考&#xff0c;助力探路前行 萤石云价格萤石云的不便于使用 家庭场景&#xff1a;成本可控与隐…

C51:用DS1302时钟读取和设置时间

因为在ds1302.c文件中包含了写ds1302&#xff08;51向ds1302写数据&#xff09;和读ds1302&#xff08;51从ds1302读数据&#xff09;的两个函数&#xff0c;我们根据文件中提供的函数来写读取时间和设置时间的函数即可ds1302.c文件源码如下&#xff0c;需要的同学可以参考一下…

webrtc整体架构

WebRTC&#xff08;Web Real-Time Communication&#xff09;是一套支持浏览器和移动应用进行实时音视频通信的开源技术标准&#xff0c;其架构设计围绕 “实时性”“低延迟”“跨平台” 和 “安全性” 展开&#xff0c;整体可分为核心引擎层、API 层、支撑服务层三大部分&…

浅析PCIe 6.0 ATS地址转换功能

在现代高性能计算和虚拟化系统中,地址转换(Address Translation)是一个至关重要的机制。随着 PCIe 设备(如 GPU、网卡、存储控制器)直接访问系统内存的能力增强,设备对虚拟内存的访问需求日益增长。 为了提升性能并确保安全访问,Address Translation Services(ATS) 应…

【前端】ikun-pptx编辑器前瞻问题二: pptx的压缩包结构,以及xml正文树及对应元素介绍

文章目录PPTX文件本质&#xff1a;一个压缩包核心文件解析1. 幻灯片内容文件 (ppt/slides/slideX.xml)2. 元素类型解析文本框元素 (p:sp)图片元素 (p:pic)单位系统开发注意事项参考工具pptx渲染路线图PPTX文件本质&#xff1a;一个压缩包 PPTX文件实际上是一个遵循Open XML标准…

分布式任务调度实战:XXL-JOB与Elastic-Job深度解析

告别传统定时任务的局限&#xff0c;拥抱分布式调度的强大与灵活 在现代分布式系统中&#xff0c;高效可靠的任务调度已成为系统架构的核心需求。面对传统方案&#xff08;如Timer、Quartz&#xff09;在分布式环境下的不足&#xff0c;开发者急需支持集群调度、故障转移和可视…

Windows 11下纯软件模拟虚拟机的设备模拟与虚拟化(仅终端和网络)

Windows 11下用GCC的C代码实现的虚拟机需要终端输入/输出&#xff08;如串口或虚拟控制台&#xff09;和网络连接&#xff0c;但不需要完整的硬件设备&#xff08;如磁盘、显卡、USB 等&#xff09;。在终端输入/输出方面&#xff0c;参考qemu的源代码&#xff0c;但不调用qemu…

CCF-GESP 等级考试 2025年6月认证Python六级真题解析

1 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;第1题 下列哪一项不是面向对象编程&#xff08;OOP&#xff09;的基本特征&#xff1f;&#xff08; &#xff09;A. 继承 (Inheritance) B. 封装 (Encapsul…

C++中的deque

1. 什么是 Deque&#xff1f; 核心概念&#xff1a; Deque 是 “Double-Ended Queue”&#xff08;双端队列&#xff09;的缩写。你可以把它想象成一个可以在两端&#xff08;头部和尾部&#xff09;高效地进行添加或删除操作的线性数据结构。关键特性&#xff1a; 双端操作&am…

GNU到底是什么,与Unix和Linux是什么关系

GNU&#xff08;发音为 /ɡnuː/&#xff0c;类似“革奴”&#xff09;是一个自由软件操作系统项目&#xff0c;由理查德斯托曼&#xff08;Richard Stallman&#xff09;于1983年发起&#xff0c;目标是创建一个完全由自由软件组成的类Unix操作系统。它的名字是一个递归缩写&a…

双指针算法介绍及使用(下)

在上一篇文章中我们已经对双指针有了一定了解&#xff0c;接下来我们通过题目来对双指针进行更好的理解。 1. leetcode 202. 快乐数 这道题使用的方法是快慢指针&#xff0c; 比如说一个数X&#xff0c;那么创建两个变量X1和X2&#xff0c;然后X1每次变化两次&#xff0c;X2变化…

Elasticsearch整合:Repository+RestClient双模式查询优化

Elasticsearch整合&#xff1a;RepositoryRestClient双模式查询优化Elasticsearch 双模式查询优化&#xff1a;Repository RestClient 整合指南一、架构设计&#xff1a;双模式协同工作流二、Repository 模式&#xff1a;快速开发最佳实践2.1 基础配置2.2 高级特性&#xff1a…

Elasticsearch 高级查询语法 Query DSL 实战指南

目录 1、DSL 概述 1.1 DSL按照查询的结构层次划分 1.2 DSL按照检索功能的用途和特性划分 1.3 示例数据准备 2、match_all ——匹配所有文档 3、精确匹配 3.1 term——单字段精确匹配查询 3.2 terms——多值精确匹配 3.3 range——范围查询 3.4 exists——是否存在查询…

DNS 服务正反向解析与 Web 集成实战:从配置到验证全流程

DNS 服务正反向解析配置全流程指南 一、前言 在网络环境中&#xff0c;DNS&#xff08;Domain Name System&#xff09;服务起着至关重要的作用&#xff0c;它负责将域名解析为 IP 地址&#xff0c;以及将 IP 地址反向解析为域名。本文将详细介绍如何配置 DNS 服务的正反向解析…

2025.07.25【宏基因组】|PathoScope 安装与使用指南

PathoScope 安装与使用指南&#xff1a;微生物组数据分析利器 作为一名生物信息工程师&#xff0c;在微生物组数据分析中&#xff0c;我们常常需要高效、准确的工具来鉴定和量化样本中的微生物组成。PathoScope 正是这样一款强大的工具&#xff0c;它能够帮助我们从高通量测序…