5-8.【OC】【Block】Block 的内存布局中,至少包含哪些关键字段?

9 阅读2分钟

从底层 C 语言的定义来看,Block 的本质是一个结构体。无论它是哪种类型的 Block,其内存布局的首部都遵循统一的规范(通常被称为 Block_layout)。

以下是 Block 内存布局中最重要的几个关键字段:


1. isa 指针

  • 作用: 指向 Block 的类对象。
  • 意义: 决定了这是一个环境 Block 的类型(_NSConcreteStackBlock_NSConcreteMallocBlock_NSConcreteGlobalBlock)。正是因为有了 isa,Block 才能被视为 Objective-C 对象并响应 retain/release

2. flags (标志位)

  • 作用: 一个整数位掩码(Bitmask)。

  • 内容: 存储了 Block 的各种状态信息,例如:

    • 该 Block 是否正在执行 copy 操作。
    • 是否捕获了外部变量。
    • 是否有 signature(签名)信息。
    • 是否包含辅助函数 copy_helperdispose_helper

3. reserved (保留字段)

  • 作用: 预留空间,目前通常为 0。

4. invoke (函数指针)

  • 作用: 这是 Block 最核心的部分。
  • 内容: 它指向 Block 内部代码块编译后生成的具体 C 函数地址。当你“调用”一个 Block 时,程序实际上是跳转到这个指针所指向的地址。

5. descriptor (描述结构体)

  • 作用: 指向一个由编译器生成的 Block_descriptor 结构体。

  • 内容: * reserved: 同样是保留位。

    • size: Block 占用的总内存大小。
    • 可选字段: 如果 Block 捕获了对象或 __block 变量,这里还会包含 copydispose 两个辅助函数的指针,用于在 Block 拷贝到堆或销毁时进行正确的内存管理。

6. 捕获的变量 (Captured Variables)

  • 位置: 紧跟在 descriptor 指针之后。
  • 内容: 如果 Block 引用了外部变量,编译器会将这些变量(或其指针、或 __block 结构体)依次排列在 Block 布局的末尾。

Block 内存布局示意图

偏移量字段名说明
0isa类对象指针 (8 bytes)
8flags状态标志位 (4 bytes)
12reserved保留位 (4 bytes)
16invoke编译后的代码实现指针 (8 bytes)
24descriptor辅助信息结构体指针 (8 bytes)
32+Captured Vars捕获的变量(值或指针,大小不固定)

一个容易被忽视的细节

descriptor 结构体中,如果 flags 指出有签名信息,那么在 size 之后还会隐藏一个 signature 字符串指针。这个签名对于 消息转发(Message Forwarding) 和一些 Hook 框架(如 Aspect)至关重要。