iOS-11.编译器优化

1,495 阅读2分钟

ios底层文章汇总

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指令封装为likelyunlikely宏。这两个宏的写法如下:

#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]