读objc_msgSend实现发现一个有趣的点

2018-12-20  本文已影响0人  陈_振

众所周知,每次从类的缓存列表中查找对应实现时,'objc_msgSend'源码中会将'SEL'与'cache.mask'进行与运算。
而有趣的地方在于每个Class类对象初始化时会为缓存分配4个'bucket',当缓存数量达到总容量的3/4时,系统会将'bucket'的数量增大'2'倍。因此'bucket'的数量始终是2的n次幂。转为2进制所有有效位均为1。基于此,才可以将'SEL'与'cache.mask'进行与运算,如果'bucket'的数量没有这个特性的话,则不能进行与运算,只能通过取余的方式(原因下面会解释),这样的话效率就会差很多。

解释:

如果'bucket'的数量不为2的n次幂,如,0x10(表示最大下标为2),此时用0和1分别与0x10进行与运算得到的结果均为0。此时只能进行取余操作才能满足要求。如果'bucket'的数量为2的n次幂,如,0x11(表示最大下标为3)则任何不同的数(转换为二进制后位数与0x11的位数一直)与0x11进行与运算都不会重复,且最大值不会超过0x11,因此可以通过与运算的方式取索引。

总结:

使用与运算比取余操作求数组下标效率要高,前提是mask的值必须为2的n次幂。

参考文章:
objc_msgSend
Memory barrier

上一篇下一篇

猜你喜欢

热点阅读