美文网首页
Swift 内联函数窥探

Swift 内联函数窥探

作者: 村口大白杨 | 来源:发表于2021-03-15 22:54 被阅读0次

内联函数(Inline Function):

如果开启了编译器优化,编译器会自动将某些函数变成内联函数(将函数调用展开成函数体),我们可以看到 Release 模式默认开启优化,并且是按照速度去优化:

比如我们有一个函数,那么一旦调用 test() 这个函数,系统就会为这个函数分配栈空间,并且在栈空间进行分配局部变量的操作,函数执行完之后会对函数栈空间进行回收:

func test() {
    print("test")
}
test()

我们思考一下,test() 这个函数里面的代码非常少,仅仅做一件事情打印,那么我们直接把 test() 函数里这行代码拿出来,这样性能不就更好吗?其实内联做的操作就是这样,将函数调用展开成函数体代码,这样就减少了函数的调用开销,不必再开辟回收函数的栈空间了。展开后代码如下:

print("test")

接下来我们运行看一下汇编代码,首先在第 14 行代码打一个断点,然后打开显示反汇编选项(Debug -> Debug Workflow -> Always show Disassembly):

1、首先编译器未开启优化的情况:

TestSwift`main:
    0x100003e40 <+0>:  pushq  %rbp
    0x100003e41 <+1>:  movq   %rsp, %rbp
    0x100003e44 <+4>:  subq   $0x10, %rsp
    0x100003e48 <+8>:  movl   %edi, -0x4(%rbp)
    0x100003e4b <+11>: movq   %rsi, -0x10(%rbp)
->  0x100003e4f <+15>: callq  0x100003e60              ; TestSwift.test() -> () at main.swift:10
    0x100003e54 <+20>: xorl   %eax, %eax
    0x100003e56 <+22>: addq   $0x10, %rsp
    0x100003e5a <+26>: popq   %rbp
    0x100003e5b <+27>: retq   

我们发现有一个 callq 0x100003e60 的操作,这句汇编代码的意思就是调用 test() 函数,所以未开启优化的情况下没有进行内联操作。

2、然后我们打开编译器优化选项:

我们在 test() 函数调用的地方设置断点,然后运行,我们发现 test() 函数没有执行,但是 “test” 字符串被打印出来了:

然后我们把断点设置到第 11 行,运行查看汇编代码

TestSwift`main:
    0x100003e00 <+0>:   pushq  %rbp
    0x100003e01 <+1>:   movq   %rsp, %rbp
    0x100003e04 <+4>:   pushq  %rbx
    0x100003e05 <+5>:   pushq  %rax
    0x100003e06 <+6>:   leaq   0x421b(%rip), %rdi        ; demangling cache variable for type metadata for Swift._ContiguousArrayStorage<Any>
    0x100003e0d <+13>:  callq  0x100003f10              ; __swift_instantiateConcreteTypeFromMangledName at <compiler-generated>
    0x100003e12 <+18>:  movl   $0x40, %esi
    0x100003e17 <+23>:  movl   $0x7, %edx
    0x100003e1c <+28>:  movq   %rax, %rdi
    0x100003e1f <+31>:  callq  0x100003f42              ; symbol stub for: swift_allocObject
    0x100003e24 <+36>:  movq   %rax, %rbx
    0x100003e27 <+39>:  movaps 0x162(%rip), %xmm0
    0x100003e2e <+46>:  movups %xmm0, 0x10(%rax)
->  0x100003e32 <+50>:  movq   0x1c7(%rip), %rax         ; (void *)0x00007fff80be2d98: type metadata for Swift.String
    0x100003e39 <+57>:  movq   %rax, 0x38(%rbx)
    0x100003e3d <+61>:  movq   $0x74736574, 0x20(%rbx)   ; imm = 0x74736574
    0x100003e45 <+69>:  movabsq $-0x1c00000000000000, %rax ; imm = 0xE400000000000000
    0x100003e4f <+79>:  movq   %rax, 0x28(%rbx)
    0x100003e53 <+83>:  movabsq $-0x1f00000000000000, %rdx ; imm = 0xE100000000000000
    0x100003e5d <+93>:  movl   $0x20, %esi
    0x100003e62 <+98>:  movl   $0xa, %ecx
    0x100003e67 <+103>: movq   %rbx, %rdi
    0x100003e6a <+106>: movq   %rdx, %r8
    0x100003e6d <+109>: callq  0x100003f3c              ; symbol stub for: Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> ()
    0x100003e72 <+114>: movq   %rbx, %rdi
    0x100003e75 <+117>: callq  0x100003f4e              ; symbol stub for: swift_release
    0x100003e7a <+122>: xorl   %eax, %eax
    0x100003e7c <+124>: addq   $0x8, %rsp
    0x100003e80 <+128>: popq   %rbx
    0x100003e81 <+129>: popq   %rbp
    0x100003e82 <+130>: retq

我们看汇编可以发现,print(“test”)代码被直接放到 main 函数当中,也就是编译器帮我们做了内联操作。

但是有一些函数是不会被内联:

1、函数体比较长的函数不会被内联(如果函数体比较长,函数被调用次数也非常多,进行内联操作生成的汇编代码会非常多,也就是机器码会变多,最终代码体积变大安装包变大);
2、递归调用不会被内联;
3、包含动态派发(类似Oc动态绑定)的函数不会被内联;

相关文章

  • Swift 内联函数窥探

    内联函数(Inline Function): 如果开启了编译器优化,编译器会自动将某些函数变成内联函数(将函数调用...

  • C++第二弹---函数

    内联函数 内联函数的定义内联函数也叫内嵌函数,他主要是解决程序运行效率。当内联函数收到编译器的指示时,即可发生内联...

  • Swift 内联序列函数sequence

    在看RxSwift文章的时候,有人说到了Sequence。恕小弟才疏学浅,在日常搬砖中没有使用到它,所以在此记录一...

  • Swift和OC函数调用的区别

    区别:1、oc是动态,swift是静态(函数内联)2、Swift编译时就确定了方法的实现,oc是运行时才确定方法的...

  • 内联函数

    内联函数 整理自内联函数百度百科 内联函数是指用inline修饰的函数(并不是所有用inline修饰的函数都是内联...

  • 《C++ Primer Plus》:函数探幽

    本章内容概览 内联函数 引用变量 按引用传递函数参数 默认参数 函数重载 函数模板 内联函数 内联函数是C++为提...

  • Kotlin系列之let、with、run、apply、also

    目录: 一、回调函数的Kotin的lambda的简化二、内联扩展函数之let三、内联函数之with四、内联扩展函数...

  • C++基础-(函数)

    C++基础 函数 内联函数 内联函数非常短的函数适合于内联函数体会到插入到发生函数调用的地方普通函数调用多次也只有...

  • C++——内联函数、函数重载、函数缺省参数

    内联函数 使用inline关键字将函数变为内联函数,函数内联是为了降低函数调用时占用的多余时间,多余时间的产生在,...

  • C++——内联函数、函数重载、函数缺省参数

    内联函数 使用inline关键字将函数变为内联函数,函数内联是为了降低函数调用时占用的多余时间,多余时间的产生在,...

网友评论

      本文标题:Swift 内联函数窥探

      本文链接:https://www.haomeiwen.com/subject/crolcltx.html