跳到主要内容

方法缓存

问题

ObjC 的方法缓存是如何工作的?

答案

cache_t 结构

struct cache_t {
struct bucket_t *_buckets; // 散列表
mask_t _mask; // 容量 - 1(用于 & 运算)
uint16_t _occupied; // 已使用数量
};

struct bucket_t {
SEL _sel; // 方法名
IMP _imp; // 函数指针
};

查找过程

缓存扩容

  • 初始容量 4
  • 使用率超过 3/4 时扩容为 2 倍
  • 扩容时清空旧缓存(而非迁移)
为什么扩容时清空?

因为缓存基于开放寻址法,扩容后 mask 变化,hash 结果不同,旧数据位置不再正确。且方法会在后续调用时重新缓存(局部性原理)。


常见面试问题

Q1: 为什么用散列表而不是数组?

答案:散列表查找时间复杂度 O(1)O(1),而数组遍历是 O(n)O(n)objc_msgSend 是所有方法调用的入口,频率极高,必须保持极致性能。

Q2: objc_msgSend 为什么用汇编实现?

答案objc_msgSend 是调用频率最高的函数。汇编可以精确控制寄存器、避免函数调用开销、尾调用优化,比 C 编译结果更快。

相关链接