1. callAlloc函数中slowpath & fastpath 引入
查看callAlloc源码实现,可看到objc源码中定义的宏slowpath & fastpath 的使用
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
//有可用的编译器优化
// checkNil 为false,!cls 也为false ,slowpath 为 false,不会执行if分支,即不会返回nil
if (slowpath(checkNil && !cls)) return nil;
//判断一个类是否有自定义的 +allocWithZone 实现,没有则走到if里面的实现
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available. // 没有可用的编译器优化
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
2.slowpath & fastpath宏的具体定义
//x很可能为真, fastpath 可以简称为 真值判断
#define fastpath(x) (__builtin_expect(bool(x), 1))
//x很可能为假,slowpath 可以简称为 假值判断
#define slowpath(x) (__builtin_expect(bool(x), 0))
__builtin_expect(EXP, N):EXP==N的概率很大,这个指令是gcc引入的,作用是允许程序员将最有可能执行的分支告诉编译器
一般将__builtin_expect
指令封装为likely
和unlikely
宏。这两个宏的写法如下:
#define likely(x) __builtin_expect(!!(x), 1) //x很可能为真
#define unlikely(x) __builtin_expect(!!(x), 0) //x很可能为假
-
__builtin_expect()
目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。 -
fastpath
定义中__builtin_expect((x),1)
表示 x 的值为真的可能性更大;即执行if
里面语句的机会更大 -
slowpath
定义中的__builtin_expect((x),0)
表示 x 的值为假的可能性更大。即执行else
里面语句的机会更大
例如:
int x, y;
if(unlikely(x > 0))
y = 1;
else
y = -1;
gcc 编译的指令会预先读取 y = -1 这条指令,这适合 x 的值大于 0 的概率比较小的情况
3.Xcode设置编译器优化
Build Setting --> Debug -->Optimization Level --> 将None 改为 fastest,smallest[-Os]