7-17.【高级特性】Existential type (any) 如何在 runtime 保存类型和 witness table?

1 阅读3分钟

在 Swift 运行时(Runtime),any 类型(即 Existential Type)的存储和分发是由一个名为 Existential Container(存在容器) 的结构体负责的。

为了让你在运行时能对一个“抹去了具体类型”的对象进行操作,容器必须不仅保存数据,还要保存如何处理这些数据的指令

以下是其在内存中的详细布局和工作机制:


1. 内存布局:5-Word 结构

在 64 位系统下,一个 any P(P 是一个协议)通常占用 40 字节,分为三部分:

组成部分长度作用
Value Buffer3 Words (24 字节)存储值本身或指向堆内存的指针。
Metadata Pointer1 Word (8 字节)指向具体类型的 Metadata(元数据)。
PWT Pointer1 Word (8 字节)指向 Protocol Witness Table(协议见证表)。

注意:如果 any 组合了多个协议(如 any P1 & P2),容器会变长,增加更多的 PWT 指针。


2. Metadata 与 VWT:管理生命周期

Metadata Pointer 指向具体类型(如 StringMyClass)的描述信息。通过这个指针,运行时可以找到该类型的 VWT (Value Witness Table)

  • VWT 的作用:它包含了一组通用的函数指针,处理与协议逻辑无关的底层操作:

    • allocate: 如何为这个类型分配内存?
    • copy: 如何拷贝这个值(是按位拷贝还是增加引用计数)?
    • destruct: 如何销毁这个值?
  • 运行时决策:当你把一个 any 变量赋值给另一个变量时,Runtime 会查找 VWT 中的 copy 函数。由于 VWT 是根据具体类型生成的,它知道该执行深拷贝还是简单的指针赋值。


3. PWT (Protocol Witness Table):实现动态分发

这是 any 类型能够调用协议方法的关键。PWT 是一个存储了函数指针的数组。

  • 内部映射:如果你定义了协议 protocol Drawable { func draw() },那么 PWT 里就会存着一个指向具体实现类(比如 Circle)中 draw 函数的指针。

  • 调用逻辑:当你执行 anyValue.draw() 时,发生了以下伪指令操作:

    1. 从 Existential Container 中读出 PWT 指针
    2. 在 PWT 表中根据偏移量找到 draw 函数的地址。
    3. Value Buffer 中取出数据(作为 self 参数)。
    4. 执行函数。

4. Value Buffer 的两种形态(运行时转换)

Runtime 会根据具体类型的大小动态决定 Buffer 的用法:

  • Inline (内联) :如果具体类型 24\le 24 字节,VWT 的 copy 指令会将数据直接写入这 24 字节中。
  • Outline (堆分配) :如果具体类型 >24> 24 字节,Runtime 会在堆上分配空间。此时 Value Buffer 的前 8 字节存储堆地址。VWT 会负责管理这块堆内存的引用计数和释放。

5. 举个例子:当你调用 any 的方法时

假设有 let a: any Drawable = Circle()

  1. 存储阶段:容器装入了 Circle 的实例(或指针),存入了 CircleMetadata 地址,以及 Circle 遵循 Drawable 协议的 PWT 地址。

  2. 调用阶段 (a.draw()):

    • 编译器生成的代码不直接查找 Circle.draw
    • 它跳转到容器中的 PWT
    • PWT 说:“对于这个 Circle 实例,draw 函数在地址 0x1234”。
    • 程序跳转到 0x1234 执行代码。

6. 性能影响总结

相比 someany 在运行时的额外开销体现在:

  1. 间接寻址:必须经过 Metadata 和 PWT 两层指针查找才能找到函数地址(无法内联)。
  2. 内存压力:大型结构体会触发动态内存分配(Heap Allocation)。
  3. Witness 表查找:每次调用协议方法都是一次动态分发。

这就是为什么 Swift 团队在 Swift 5.7+ 中极力推崇使用 some(Opaque types),除非你确实需要在一个集合里存储不同类型的对象(Heterogeneous collection)。