Objective-C Runtime — cache_t Layout
apple-oss-distributions / objc4 · latest · sizeof(cache_t) == 2 * sizeof(void*) == 16 bytes
整体内存布局(64-bit 内联 mask,最常见的 arm64 / x86_64)
cache_t  16 bytes total
+0  ·  8 bytes
bucket_t *
桶数组指针
低位存 buckets 地址,通过 ISA_MASK 类似的操作提取
mask
桶数 - 1(内联)
内联方案:mask 塞进高位 bit,和指针共享 8 字节
↳ _bucketsAndMaybeMask (uintptr_t) — 内联方案将 bucket_t* 和 mask 压缩在同一个 64-bit 字段
+8  ·  8 bytes  (union)
_disguisedPreoptCacheSignature
uint32_t · 预优化缓存签名
用于校验 _originalPreoptCache 是否有效
_occupied
uint16_t · 已用桶数
已放入缓存的方法数量,超过 3/4 触发扩容
_flags
uint16_t · 类元信息
16 bit 存 has_cxx_dtor / instanceSize 等标志
↳ 或  _originalPreoptCache (preopt_cache_t*) — 指向 dyld 共享缓存中预构建的方法缓存(两者互斥)

+8 字节 union — 两种状态互斥
运行时构建的缓存
uint32_t _disguisedPreoptCacheSignature
uint16_t _occupied已占用桶数
uint16_t _flags类元信息位
↳ 运行时 insert() 写入方法后使用
── OR(互斥)──
dyld 预优化缓存
preopt_cache_t * _originalPreoptCache
↳ 系统类在 dyld 共享缓存中已预构建
↳ 直接指向现成缓存,不需要运行时构建
↳ isConstantOptimizedCache() 返回 true
bucket_t — 缓存桶单元
bucket_t  16 bytes
SEL
_sel · 8 bytes
方法选择器,散列键
IMP
_imp · 8 bytes
函数指针,命中后直接跳转
散列地址:(sel ^ (sel >> shift)) & mask
冲突:向前线性探测(--index & mask)
占用 > 3/4 时触发 reallocate() 扩容
_bucketsAndMaybeMask 内联方案
内联 mask(64-bit 平台)
bit 0bucket_t* 指针 ←→ mask(高位)bit 63
buckets() → bits & bucketsMask 提取指针
mask() → bits >> maskShift 提取 mask

_flags (uint16_t) — 16 bit 位域详解
_flags  16 bits · 存在 cache_t 里避免每次去 class_ro_t 取
bit 0 ← instanceSize (bit 3~11) → bit 15
bit
宏名
含义
0
HAS_CXX_DTOR
有 C++ 析构 / .cxx_destruct  arm64
1
HAS_CXX_CTOR
有 C++ 构造 / .cxx_construct  arm64
2
META
是元类  arm64
3~11
ALLOC_MASK
对齐后的实例大小(+ DELTA16 偏移编码) LP64
12
HAS_CUSTOM_DEALLOC_INITIATION
有自定义 dealloc 触发逻辑  all
13
REQUIRES_RAW_ISA
实例必须用裸 isa(不能用 nonpointer) all
14
HAS_DEFAULT_AWZ
有默认 alloc / allocWithZone(存元类) all
15
HAS_DEFAULT_CORE
有默认 new / self / class / retain / release…  all

fastInstanceSize — 实例大小编码在 _flags bit 3~11
快速实例大小(避免每次 alloc 走 class_ro_t)
写入 setFastInstanceSize
sizeBits = word_align(newSize) + DELTA16
sizeBits &= ALLOC_MASK   // 只保留 bit 3~11
_flags = (flags & ~ALLOC_MASK) | sizeBits
读取 fastInstanceSize
size = _flags & ALLOC_MASK
return align16(size + extra - DELTA16)
// 还原真实字节大小
↳ alloc 快速路径直接读 cache._flags,一次内存访问拿到大小,无需走 bits → class_rw_t → class_ro_t

CACHE_MASK_STORAGE — 四种平台方案对比
OUTLINED
32-bit(!LP64)
_bucketsAndMaybeMaskbucket_t*
── union ──
_mask独立字段
_occupieduint16_t
_flags❌ 无
OUTLINED
64-bit(LP64)
_bucketsAndMaybeMaskbucket_t*
── union ──
_mask独立字段
_occupieduint16_t
_flags✅ 有
INLINE mask
64-bit · arm64 / x86_64
_bucketsAndMaybeMaskptr + mask
── union ──
_disguisedPreoptSiguint32_t
_occupieduint16_t
_flags✅ 有
INLINE mask
32-bit · armv7k
_bucketsAndMaybeMaskptr + mask
── union ──
_occupieduint16_t
_flags✅ 有
_disguisedPreoptSig❌ 无