本章节是对于上个章节的补充说明,通过流程图与真机汇编解析快速查找,顺便引出下一章的慢速查找。而最后的cache_t
的扩容是对cache_t
的补充说明!
一、缓存查询流程图
- 流程图:
graph TB
A[objc_msgSend] -->B{cmp p0, #0<br>判断接受者是否存在?<br>}
B -->|否| D[通过对象isa获取class]
B -->|是| C{是否支持<br>taggegpointer对象}
C -->|是| E{小对象或者空 <br>判断LNilOrTagged<br>}
D --> G[获取isa完毕 LGetIsaDone]
E -->|小对象Isa处理| G
C -->|否| F[直接返回空LReturnZero]
E -->|空| F
G --> H[开去缓存查找流程 <br>CacheLookup NORMAL<br>]
H --> I[通过类的指针平移16得到<br>cacheldr p11,x16 #CACHE<br>]
I --> J[通过获取的mask_buckets掩码运算得到<br>bucketsand p10,p11, #0x0000ffffffffffff<br>]
I --> K1[通过逻辑右移得到<br>mask p11, LSR #48<br>]
K1 --> K2[通过and p12, p1 计算哈希函数<br>得到下标 _cmd &mask<br>]
J --> K["p12=buckets+((_cmd & mask)<<(1+PTRSHIFT))<br>通过内存平移得到bucket<br>"]
K2 --> K
K -->|第一次通过下标向前查找| L["通过bucket结构体得到<br>{imp,sel}=*bucket--<br>"]
L --> M{判断要查询sel和当前_cmd<br>是否相等<br>}
M -->|是| N[命中缓存CacheHit NORMAL]
M -->|否| Q{"sel是否为0(nil)"}
Q -->|是| W["找不到缓存sel或者结束循环<br>进入慢速查找_objc_msgSend_uncache"]
Q -->|否| O{"判断当前查询bucket是否为<br>第一个元素<br>bucket == buckets<br>"}
O -->|是| P["把当前查询bucket设置为最后一个元素<br>p12 = buckets + (mask << 1+PTRSHIFT)<br>"]
O -->|否| L
P --> P1["计算出下标index所在bucket(first_probed)"]
P1 -->|第二次从buckets最后开始向前查找| L1["通过bucket结构体得到
{imp,sel}=*bucket--"]
L1 --> M1{判断要查询sel和当前_cmd<br>是否相等<br>}
M1 -->|是| N
M1 -->|否| O1{"判断当前查询sel是存在<br>且当前bucket大于first_probed"}
O1 -->|否| W
O1 -->|是| L1
二、汇编流程图简化讲解
- 判断当前接收者是否存在
cmp p0, #0
- 通过
isa
拿到class
ldr p14, [x0] // p14 = raw isa
GetClassFromIsa_p16 p14, 1, x0 // p16 = class
- 进入
CacheLookup
流程,两种结果;找到并抛出imp
,没找到通过__objc_msgSend_uncached
进入后续的慢速查找流程
CacheLookup NORMAL, _objc_msgSend,__objc_msgSend_uncached
LLookupStart
查找开始,这里根据模拟器、真机、arm64
架构,A12
以上芯片情况做了汇编区分,下面只列出满足条件的汇编
//模拟器
CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS //mac电脑(x86-64)、arm64的模拟器
//真机
CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
//amr64真机
CONFIG_USE_PREOPT_CACHES = 1
//是判断编译器是否支持指针身份验证功能,针对arm64e
//A12以上芯片(支持arm64e结构)
__has_feature(ptrauth_calls)
- 将
isa
偏移16
个字节,由p11 = mask|buckets
得到cache_t
ldr p11, [x16, #CACHE]
- 判断
cache_t
的0号位置是否为0
?如果不为0,执行LLookupPreopt
,去找共享缓存;如果为0,将cache_t(_bucketsAndMaybeMask) & #0x0000ffffffffffff
,得到了buckets
tbnz p11, #0, LLookupPreopt\Function
and p10, p11, #0x0000ffffffffffff // p10 = buckets
- 将
sel
右移7位在与自己做逻辑异或^赋值给p12
,将cache_t(_bucketsAndMaybeMask)
右移48
位,可以得到mask
,最后将p12 & mask
,hash
算法得到了查找方法_cmd
对应buckets
的下标index
,即first_probed
//p1 = _cmd, eor是异或,p12 = p1 ^(p1 >> 7) = _cmd ^ (_cmd >> 7)
eor p12, p1, p1, LSR #7
//p11 >> 48 = _bucketsAndMaybeMask >> 48 = mask
//p12 = p12 & (p11 >> 48) = _cmd ^ (_cmd >> 7) & mask
//p12 = (_cmd ^ (_cmd >> 7)) & mask 这一步的作用就是hash求下标index
and p12, p12, p11, LSR #48 // x12 = (_cmd ^ (_cmd >> 7)) & mask
clang
得到c++源码:
static inline mask_t cache_hash(SEL sel, mask_t mask)
{
uintptr_t value = (uintptr_t)sel;
#if CONFIG_USE_PREOPT_CACHES
value ^= value >> 7;
#endif
return (mask_t)(value & mask);
}
- 由于上面可知第一个查找的
bucket_t
的下标index
,那么接下来就是通过偏移到这个bucket_t
拿到里面的sel
与imp
,这里是将index
向左偏移4
位,理解为index * (1 << 4)
即index * 16
,得到的是偏移距离。偏移4
位是因为一个bucket_t
占16字节,最后再加上buckets
地址,就得到了第一个要比较的bucket_t
。
add p13, p10, p12, LSL #(1+PTRSHIFT)
// p13 = buckets + ((_cmd & mask) << (1+PTRSHIFT))
- 将
p13
内的imp
和sel
拿出来分别存在p17
和p9
,再执行bucket--
向前移位即index--
。如果sel != _cmd
,就执行3f
。判断sel
是否存在?不存在时就进入慢速查找__objc_msgSend_uncached
;存在判断当前bucket
是不是buckets
范围内?如果在范围内,继续循环,回到1b
,取出向前移位的imp
和sel
。如果这个过程找到了目标_cmd
,跳转到2
,命中缓存,结束查找。
// do{
1: ldp p17, p9, [x13], #-BUCKET_SIZE // {imp, sel} = *bucket--
cmp p9, p1 // if (sel != _cmd) {
b.ne 3f // scan more
// }
// else {
2: CacheHit \Mode // hit: call or return imp
// }
3: cbz p9, \MissLabelDynamic // if (sel == 0) goto Miss;
cmp p13, p10 // } while (bucket >= buckets)
b.hs 1b
- 如果找到
bucket
首位都未匹配到目标_cmd
,则直接跳转至mask
处bucket
(末位bucket_t
),重新倒序查找缓存内的bucket_t
,这里还获取了第一次探查的位置index
,为了避免重复探查。4
内操作为将bucket_t
的imp
和sel
拿出来赋值给p17
和p9
,再执行bucket--
向前查找缓存方法,比较sel
与_cmd
是否相同?如果相同,执行2b
,命中缓存;如果不同就判断p9
即sel
是否存在?与判断当前bucket
是否大于第一次探查的bucket
?,如果上述条件都满足,则继续循环4b
,直到命中缓存。如果全部都搜索完还没有命中,进入慢速查找__objc_msgSend_uncached
流程。
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16///arm64真机
add p13, p10, p11, LSR #(48 - (1+PTRSHIFT))
// p13 = buckets + (mask << 1+PTRSHIFT)
add p12, p10, p12, LSL #(1+PTRSHIFT)
// p12 = first probed bucket
// do {
4: ldp p17, p9, [x13], #-BUCKET_SIZE // {imp, sel} = *bucket--
cmp p9, p1 // if (sel == _cmd)
b.eq 2b // goto hit
cmp p9, #0 // } while (sel != 0 &&
ccmp p13, p12, #0, ne // bucket > first_probed)
b.hi 4b
三、真机调试(汇编分析)
- 案例源码:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
@interface CJPerson : NSObject
- (void)saySomething;
@end
@implementation CJPerson
- (void)saySomething{
NSLog(@"%s",__func__);
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
CJPerson *p = [CJPerson alloc];
[p saySomething];
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
确认当前探索的类与方法
真机汇编分解图解:
libobjc.A.dylib`objc_msgSend:
//x0为消息接收者receiver,比较x0与0,如果没有接收者,则此次objc_msgSend没有意义(x0 = 0x00000002803b8180)
-> 0x19ef9b1c0 <+0>: cmp x0, #0x0 ; =0x0
0x19ef9b1c4 <+4>: b.le 0x19ef9b28c ; <+204>
//将x0里面的实例对象p的isa赋值给x13
//即将寄存器x0地址为0x00000002803b8180的字数据读入到寄存器x14(x14 = 0x01000001026cd441 (0x00000001026cd441) (void *)0x4800000001026cd4)
//具体可以看`底层原理(三)`里的x/4gx 0x00000002803b8180
0x19ef9b1c8 <+8>: ldr x14, [x0]
//将x14&0x7ffffffffffff8(即isa & ISA_MASK获取到类CJPerson)赋值给x16(x16 = 0x00000001026cd440 (void *)0x00000001026cd418: CJPerson)
0x19ef9b1cc <+12>: and x16, x14, #0x7ffffffffffff8
//将 x0赋值给x10(即将实例对象p复制到x10 = 0x00000002803b8180)
0x19ef9b1d0 <+16>: mov x10, x0
//将x10内的内容数据从48位开始更为0x6ae1(x10 = 0x6ae10002803b8180)
0x19ef9b1d4 <+20>: movk x10, #0x6ae1, lsl #48
//(x16 = 0x00000001026cd440 (void *)0x00000001026cd418: CJPerson)
0x19ef9b1d8 <+24>: autda x16, x10
//将x16赋值给x15(x15 = 0x00000001026cd440 (void *)0x00000001026cd418: CJPerson)
0x19ef9b1dc <+28>: mov x15, x16
//将CJPerson的isa右移16位读取cache_t, px16+0x10(x/4gx 0x00000001026cd440)后读取内容数据到(x11 = 0x00010002801be4a0)
0x19ef9b1e0 <+32>: ldr x11, [x16, #0x10]
//判断w11(w11 = 0x801be4a0)的第0位是否为0,为0继续往下走,不为0跳转到下面0x19ef9b240地址执行
0x19ef9b1e4 <+36>: tbnz w11, #0x0, 0x19ef9b240 ; <+128>
//x10 = x11 & 0xffffffffffff(即x10 = 0x00000002801be4a0)
0x19ef9b1e8 <+40>: and x10, x11, #0xffffffffffff
//x12 = _cmd ^ (_cmd >> 7)即(传入方法参数x1 = 0x00000001026c718e "saySomething")(x12为0x000000010068a96d = 0x00000001026c718e ^ 0x000000000204d8e3)
0x19ef9b1ec <+44>: eor x12, x1, x1, lsr #7
//mask = x11 >> 48 即(0x00010002801be4a0 >> 48 = 0x0000000000000001)
//x12 = mask & x12 即(x12 = 0x0000000000000001)为第一个检索位置即first_prepot
0x19ef9b1f0 <+48>: and x12, x12, x11, lsr #48
//buckets + first_preop 即 x13 = (0x00000002801be4a0 + (0x01 << 4 = 0x10)) = 0x00000002801be4b0
0x19ef9b1f4 <+52>: add x13, x10, x12, lsl #4
//p x13 - 0x10得到老版本地区 即x/4gx 0x00000002801be4b0取出前两位分别赋值 x17 = 0xdd1a3d019efbeb34, x9 = 0x00000001da0a38ae
0x19ef9b1f8 <+56>: ldp x17, x9, [x13], #-0x10
//比较x9与x1,x9 == x1 即0x00000001da0a38ae == 0x00000001026c718e
0x19ef9b1fc <+60>: cmp x9, x1
//不等跳转到0x19ef9b210
0x19ef9b200 <+64>: b.ne 0x19ef9b210 ; <+80>
// x10 = x10异或x1
0x19ef9b204 <+68>: eor x10, x10, x1
// x10 = x10 ^ x16
0x19ef9b208 <+72>: eor x10, x10, x16
//
0x19ef9b20c <+76>: brab x17, x10
//
0x19ef9b210 <+80>: cbz x9, 0x19ef9b600 ; _objc_msgSend_uncached
//比较x13与x10 即0x00000002801be4a0 == 0x00000002801be4a0
0x19ef9b214 <+84>: cmp x13, x10
//相等时跳转到0x19ef9b1f8从新开始 但是x13 = 0x00000002801be4a0比之前0x00000002801be4b0-0x10
0x19ef9b218 <+88>: b.hs 0x19ef9b1f8 ; <+56>
//不相等时,x13 = (x10 = 0x00000002801be4a0) + ((x11 = 0x00010002801be4a0)>>44 = 0x0000000000000010) = 0x00000002801be4b0
0x19ef9b21c <+92>: add x13, x10, x11, lsr #44
//x12 = (x10 = 0x00000002801be4a0) + (x12 = 0x0000000000000001 << 4) = 0x00000002801be4b0
0x19ef9b220 <+96>: add x12, x10, x12, lsl #4
//取出x13指向数据前两位x17 = 0xdd1a3d019efbeb34, x9 = 0x00000001da0a38ae
0x19ef9b224 <+100>: ldp x17, x9, [x13], #-0x10
//比较x9与x1 x9 = 0x00000001da0a38ae x1 = 0x00000001026c718e "saySomething"
0x19ef9b228 <+104>: cmp x9, x1
//相等时跳转0x19ef9b204
0x19ef9b22c <+108>: b.eq 0x19ef9b204 ; <+68>
//判断x9是否为0x00
0x19ef9b230 <+112>: cmp x9, #0x0 ; =0x0
//x13 = 0x00000002801be4a0, x12 = 0x00000002801be4b
0x19ef9b234 <+116>: ccmp x13, x12, #0x0, ne
0x19ef9b238 <+120>: b.hi 0x19ef9b224 ; <+100>
//跳转到0x19ef9b600执行_objc_msgSend_uncached(慢速查找)
0x19ef9b23c <+124>: b 0x19ef9b600 ; _objc_msgSend_uncached
//x10 = x11 & 0x7ffffffffffffe
0x19ef9b240 <+128>: and x10, x11, #0x7ffffffffffffe
0x19ef9b244 <+132>: autdb x10, x16
0x19ef9b248 <+136>: adrp x9, 239235
0x19ef9b24c <+140>: add x9, x9, #0x4ae ; =0x4ae
0x19ef9b250 <+144>: sub x12, x1, x9
0x19ef9b254 <+148>: lsr x17, x11, #55
0x19ef9b258 <+152>: lsr w9, w12, w17
0x19ef9b25c <+156>: lsr x17, x11, #60
0x19ef9b260 <+160>: mov x11, #0x7fff
0x19ef9b264 <+164>: lsr x11, x11, x17
0x19ef9b268 <+168>: and x9, x9, x11
0x19ef9b26c <+172>: ldr x17, [x10, x9, lsl #3]
0x19ef9b270 <+176>: cmp x12, w17, uxtw
0x19ef9b274 <+180>: b.ne 0x19ef9b280 ; <+192>
0x19ef9b278 <+184>: sub x17, x16, x17, lsr #32
0x19ef9b27c <+188>: br x17
0x19ef9b280 <+192>: ldursw x9, [x10, #-0x8]
0x19ef9b284 <+196>: add x16, x16, x9
0x19ef9b288 <+200>: b 0x19ef9b1e0 ; <+32>
0x19ef9b28c <+204>: b.eq 0x19ef9b2b0 ; <+240>
0x19ef9b290 <+208>: and x10, x0, #0x7
0x19ef9b294 <+212>: asr x11, x0, #55
0x19ef9b298 <+216>: cmp x10, #0x7 ; =0x7
0x19ef9b29c <+220>: csel x12, x11, x10, eq
0x19ef9b2a0 <+224>: adrp x10, 320424
0x19ef9b2a4 <+228>: add x10, x10, #0x820 ; =0x820
0x19ef9b2a8 <+232>: ldr x16, [x10, x12, lsl #3]
0x19ef9b2ac <+236>: b 0x19ef9b1dc ; <+28>
0x19ef9b2b0 <+240>: mov x1, #0x0
0x19ef9b2b4 <+244>: movi d0, #0000000000000000
0x19ef9b2b8 <+248>: movi d1, #0000000000000000
0x19ef9b2bc <+252>: movi d2, #0000000000000000
0x19ef9b2c0 <+256>: movi d3, #0000000000000000
0x19ef9b2c4 <+260>: ret
0x19ef9b2c8 <+264>: nop
0x19ef9b2cc <+268>: nop
0x19ef9b2d0 <+272>: nop
0x19ef9b2d4 <+276>: nop
0x19ef9b2d8 <+280>: nop
0x19ef9b2dc <+284>: nop
四、补充内容
关于类cache_t内存扩容在真机情况下的源码模拟
- 部分关键源码:
typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient
//preopt_cache_entry_t源码模仿
struct ff_preopt_cache_entry_t {
int64_t raw_imp_offs : 38; // actual IMP offset from the isa >> 2
uint64_t sel_offs : 26;
inline int64_t imp_offset() const {
return raw_imp_offs << 2;
}
};
//preopt_cache_t源码模仿
struct ff_preopt_cache_t {
int64_t fallback_class_offset;
union {
struct {
uint16_t shift : 5;
uint16_t mask : 11;
};
uint16_t hash_params;
};
uint16_t occupied : 14;
uint16_t has_inlines : 1;
uint16_t padding : 1;
uint32_t unused : 31;
uint16_t bit_one : 1;
struct ff_preopt_cache_entry_t entries[];
inline int capacity() const {
return mask + 1;
}
};
//bucket_t源码模仿
struct ff_bucket_t {
IMP _imp;
SEL _sel;
};
//cache_t源码模仿
struct ff_cache_t {
uintptr_t _bucketsAndMaybeMask; // 8
union {
struct {
uint32_t _unused;
uint16_t _occupied;
uint16_t _flags;
};
struct ff_preopt_cache_t *_originalPreoptCache; // 8
};
static constexpr uintptr_t maskShift = 48;
static constexpr uintptr_t maskZeroBits = 4;
static constexpr uintptr_t maxMask = ((uintptr_t)1 << (64 - maskShift)) - 1;
static constexpr uintptr_t bucketsMask = ((uintptr_t)1 << (maskShift - maskZeroBits)) - 1;
static constexpr uintptr_t preoptBucketsMarker = 1ul;
static constexpr uintptr_t preoptBucketsMask = 0x007ffffffffffffe;
ff_bucket_t *buckets() {
return (ff_bucket_t *)(_bucketsAndMaybeMask & bucketsMask);
}
uint32_t mask() const {
return _bucketsAndMaybeMask >> maskShift;
}
unsigned capacity() const {
return mask() ? mask()+1 : 0;
}
mask_t occupied() const {
return _occupied;
}
};
//class_data_bits_t源码模仿
struct ff_class_data_bits_t {
uintptr_t objc_class;
};
//类源码模仿
struct ff_objc_class {
Class isa;
Class superclass;
struct ff_cache_t cache;
struct ff_class_data_bits_t bits;
};
void test(Class cls) {
//将person的类型转换成自定义的源码ff_objc_class类型,方便后续操作
struct ff_objc_class *pClass = (__bridge struct ff_objc_class *)(cls);
struct ff_cache_t cache = pClass->cache;
struct ff_bucket_t * buckets = cache.buckets();
uintptr_t _bucketsAndMaybeMask = cache._bucketsAndMaybeMask;
uintptr_t mask = cache.mask();
NSLog(@"class: %p", pClass);
NSLog(@"_bucketsAndMaybeMask: 0x%lx, mask: %lu", _bucketsAndMaybeMask, mask);
//打印当前有多少个方法缓存与最大缓存数量
NSLog(@"%lu-%lu",cache.occupied(), cache.capacity());
//打印buckets
for (int i = 0; i < mask + 1; i++ ) {
SEL sel = buckets[i]._sel;
IMP imp = buckets[i]._imp;
NSLog(@"%@-%p",NSStringFromSelector(sel),imp);
}
}
int main(int argc, char * argv[]) {
@autoreleasepool {
//给person分配内存
FFPerson *person = [FFPerson alloc];
//调用方法
[person likeGirls];
test(person.class);
[person likeFoods];
test(person.class);
[person likeFlower];
test(person.class);
[person likeStudy];
test(person.class);
[person enjoyLift];
test(person.class);
[person lnspireCreativity];
test(person.class);
[person likeGirls];
test(person.class);
[person likeFoods];
test(person.class);
[person likeFlower];
test(person.class);
[person likeStudy];
test(person.class);
[person enjoyLift];
test(person.class);
[person lnspireCreativity];
test(person.class);
[person likePlay];
test(person.class);
[person likeSleep];
test(person.class);
[person likeRead];
test(person.class);
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
- 打印结果:
2023-01-01 03:26:22.960430+0800 objc_test[4652:874431] -[FFPerson likeGirls]
2023-01-01 03:26:22.961419+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:22.961476+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x1000281eae820, mask: 1
2023-01-01 03:26:22.961505+0800 objc_test[4652:874431] 1-2
2023-01-01 03:26:22.961532+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.961688+0800 objc_test[4652:874431] likeGirls-0x1064a881002e941c
2023-01-01 03:26:22.961721+0800 objc_test[4652:874431] -[FFPerson likeFoods]
2023-01-01 03:26:22.961745+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:22.961770+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x1000281eae820, mask: 1
2023-01-01 03:26:22.961801+0800 objc_test[4652:874431] 2-2
2023-01-01 03:26:22.961868+0800 objc_test[4652:874431] likeFoods-0xfc701301002e9458
2023-01-01 03:26:22.961917+0800 objc_test[4652:874431] likeGirls-0x1064a881002e941c
2023-01-01 03:26:22.961997+0800 objc_test[4652:874431] -[FFPerson likeFlower]
2023-01-01 03:26:22.962146+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:22.962199+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x3000280ba0040, mask: 3
2023-01-01 03:26:22.962259+0800 objc_test[4652:874431] 1-4
2023-01-01 03:26:22.962493+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.962608+0800 objc_test[4652:874431] likeFlower-0xbd2e4f81002e9494
2023-01-01 03:26:22.962658+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.962734+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.962815+0800 objc_test[4652:874431] -[FFPerson likeStudy]
2023-01-01 03:26:22.962850+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:22.962927+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x3000280ba0040, mask: 3
2023-01-01 03:26:22.962977+0800 objc_test[4652:874431] 2-4
2023-01-01 03:26:22.963027+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.963257+0800 objc_test[4652:874431] likeFlower-0xbd2e4f81002e9494
2023-01-01 03:26:22.963307+0800 objc_test[4652:874431] likeStudy-0x5015af01002e94d0
2023-01-01 03:26:22.963370+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.963467+0800 objc_test[4652:874431] -[FFPerson enjoyLift]
2023-01-01 03:26:22.963495+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:22.963568+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x3000280ba0040, mask: 3
2023-01-01 03:26:22.963617+0800 objc_test[4652:874431] 3-4
2023-01-01 03:26:22.963733+0800 objc_test[4652:874431] enjoyLift-0x925c6081002e950c
2023-01-01 03:26:22.963844+0800 objc_test[4652:874431] likeFlower-0xbd2e4f81002e9494
2023-01-01 03:26:22.963890+0800 objc_test[4652:874431] likeStudy-0x5015af01002e94d0
2023-01-01 03:26:22.963918+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:22.963968+0800 objc_test[4652:874431] -[FFPerson lnspireCreativity]
2023-01-01 03:26:22.964015+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:22.964067+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x3000280ba0040, mask: 3
2023-01-01 03:26:22.964121+0800 objc_test[4652:874431] 4-4
2023-01-01 03:26:22.964217+0800 objc_test[4652:874431] enjoyLift-0x925c6081002e950c
2023-01-01 03:26:22.964329+0800 objc_test[4652:874431] likeFlower-0xbd2e4f81002e9494
2023-01-01 03:26:22.964441+0800 objc_test[4652:874431] likeStudy-0x5015af01002e94d0
2023-01-01 03:26:22.964541+0800 objc_test[4652:874431] lnspireCreativity-0xc8031381002e9548
2023-01-01 03:26:31.091214+0800 objc_test[4652:874431] -[FFPerson likeGirls]
2023-01-01 03:26:31.091390+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.091427+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.091457+0800 objc_test[4652:874431] 1-8
2023-01-01 03:26:31.091485+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091553+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.091587+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091612+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091637+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091709+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091754+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091814+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.091904+0800 objc_test[4652:874431] -[FFPerson likeFoods]
2023-01-01 03:26:31.091955+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.092070+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.092130+0800 objc_test[4652:874431] 2-8
2023-01-01 03:26:31.092189+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.092295+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.092431+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.092498+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.092594+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.092779+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.092815+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.092858+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:31.092889+0800 objc_test[4652:874431] -[FFPerson likeFlower]
2023-01-01 03:26:31.092960+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.093032+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.093079+0800 objc_test[4652:874431] 3-8
2023-01-01 03:26:31.093126+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.093232+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.093267+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.093339+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.093444+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.093599+0800 objc_test[4652:874431] likeFlower-0x2c78f181002e9494
2023-01-01 03:26:31.093634+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.093673+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:31.093707+0800 objc_test[4652:874431] -[FFPerson likeStudy]
2023-01-01 03:26:31.093748+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.093827+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.093907+0800 objc_test[4652:874431] 4-8
2023-01-01 03:26:31.094017+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.094114+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.094216+0800 objc_test[4652:874431] likeStudy-0x76095081002e94d0
2023-01-01 03:26:31.094259+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.094310+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.094409+0800 objc_test[4652:874431] likeFlower-0x2c78f181002e9494
2023-01-01 03:26:31.094441+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.094494+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:31.094542+0800 objc_test[4652:874431] -[FFPerson enjoyLift]
2023-01-01 03:26:31.094587+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.094640+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.094714+0800 objc_test[4652:874431] 5-8
2023-01-01 03:26:31.094794+0800 objc_test[4652:874431] enjoyLift-0xa35b7c01002e950c
2023-01-01 03:26:31.094846+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.094886+0800 objc_test[4652:874431] likeStudy-0x76095081002e94d0
2023-01-01 03:26:31.094967+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.095012+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.095101+0800 objc_test[4652:874431] likeFlower-0x2c78f181002e9494
2023-01-01 03:26:31.095156+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.095215+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:31.095307+0800 objc_test[4652:874431] -[FFPerson lnspireCreativity]
2023-01-01 03:26:31.095394+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.095483+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.095592+0800 objc_test[4652:874431] 6-8
2023-01-01 03:26:31.095690+0800 objc_test[4652:874431] enjoyLift-0xa35b7c01002e950c
2023-01-01 03:26:31.095761+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.095834+0800 objc_test[4652:874431] likeStudy-0x76095081002e94d0
2023-01-01 03:26:31.095912+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.095993+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.096094+0800 objc_test[4652:874431] likeFlower-0x2c78f181002e9494
2023-01-01 03:26:31.096194+0800 objc_test[4652:874431] lnspireCreativity-0x371a8f01002e9548
2023-01-01 03:26:31.096235+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:31.096284+0800 objc_test[4652:874431] -[FFPerson likePlay]
2023-01-01 03:26:31.096388+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.096431+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.096478+0800 objc_test[4652:874431] 7-8
2023-01-01 03:26:31.096542+0800 objc_test[4652:874431] enjoyLift-0xa35b7c01002e950c
2023-01-01 03:26:31.096628+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.096724+0800 objc_test[4652:874431] likeStudy-0x76095081002e94d0
2023-01-01 03:26:31.096766+0800 objc_test[4652:874431] likePlay-0x425e3e81002e9584
2023-01-01 03:26:31.096829+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:31.096903+0800 objc_test[4652:874431] likeFlower-0x2c78f181002e9494
2023-01-01 03:26:31.096997+0800 objc_test[4652:874431] lnspireCreativity-0x371a8f01002e9548
2023-01-01 03:26:31.097087+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:31.097157+0800 objc_test[4652:874431] -[FFPerson likeSleep]
2023-01-01 03:26:31.097239+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:31.097320+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0x70002830a0080, mask: 7
2023-01-01 03:26:31.097386+0800 objc_test[4652:874431] 8-8
2023-01-01 03:26:31.097511+0800 objc_test[4652:874431] enjoyLift-0xa35b7c01002e950c
2023-01-01 03:26:31.097587+0800 objc_test[4652:874431] likeGirls-0x56e7181002e941c
2023-01-01 03:26:31.097634+0800 objc_test[4652:874431] likeStudy-0x76095081002e94d0
2023-01-01 03:26:31.097705+0800 objc_test[4652:874431] likePlay-0x425e3e81002e9584
2023-01-01 03:26:31.097813+0800 objc_test[4652:874431] likeSleep-0x2273e801002e95c0
2023-01-01 03:26:31.097905+0800 objc_test[4652:874431] likeFlower-0x2c78f181002e9494
2023-01-01 03:26:31.098022+0800 objc_test[4652:874431] lnspireCreativity-0x371a8f01002e9548
2023-01-01 03:26:31.098108+0800 objc_test[4652:874431] likeFoods-0xb4368481002e9458
2023-01-01 03:26:44.559761+0800 objc_test[4652:874431] -[FFPerson likeRead]
2023-01-01 03:26:44.559909+0800 objc_test[4652:874431] class: 0x1002f10e0
2023-01-01 03:26:44.559946+0800 objc_test[4652:874431] _bucketsAndMaybeMask: 0xf0002822a4100, mask: 15
2023-01-01 03:26:44.559976+0800 objc_test[4652:874431] 1-16
2023-01-01 03:26:44.560006+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560041+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560067+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560093+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560184+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560252+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560366+0800 objc_test[4652:874431] likeRead-0x4216ad81002e95fc
2023-01-01 03:26:44.560446+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560475+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560502+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560528+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560618+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560679+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560708+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560768+0800 objc_test[4652:874431] (null)-0x0
2023-01-01 03:26:44.560866+0800 objc_test[4652:874431] (null)-0x0
INIT_CACHE_SIZE_LOG2
#if CACHE_END_MARKER || (__arm64__ && !__LP64__)
INIT_CACHE_SIZE_LOG2 = 2,
#else
INIT_CACHE_SIZE_LOG2 = 1,
#endif
cache_fill_ratio
#if __arm__ || __x86_64__ || __i386__
#define CACHE_END_MARKER 1
static inline mask_t cache_fill_ratio(mask_t capacity) {
return capacity * 3 / 4;
}
#elif __arm64__ && !__LP64__
#define CACHE_END_MARKER 0
static inline mask_t cache_fill_ratio(mask_t capacity) {
return capacity * 3 / 4;
}
#elif __arm64__ && __LP64__
#define CACHE_END_MARKER 0
static inline mask_t cache_fill_ratio(mask_t capacity) {
return capacity * 7 / 8;
}
#define CACHE_ALLOW_FULL_UTILIZATION 1
#else
#error unknown architecture
#endif
- 结论:
-
iPhoneXs
,初始缓存容量为2(INIT_CACHE_SIZE = (1 << 1)
) -
真机扩容按照大于7/8的规则,2倍扩容,所以扩容规律2-> 4 -> 8 -> 16 -> 2^n
-
x86_64
架构初始容量为4(INIT_CACHE_SIZE = (1 << 2)
) -
模拟器扩容按照大于等于
3/4
的规则,2倍扩容,扩容规律4 -> 8 -> 16 -> 2^(n+1)