调用函数时为什么会有开销?

时间:2015-08-03 04:14:37

标签: c performance optimization memory-management overhead

通常,人们会谈到在程序中调用产生一定量开销的函数,或者一组不可避免的附加问题和环境。这可以更好地解释并与没有函数调用的类似程序进行比较吗?

4 个答案:

答案 0 :(得分:3)

另请参阅herehere,了解内联何时有意义。

  • <强>内联

    通常,您只能向编译器建议inline函数,但编译器可能会另有决定。 Visual Studio提供了自己的forceinline关键字。某些功能无法内联,例如当它们是递归的或者在编译时无法确定目标函数时(通过函数表调用,在C ++中调用虚函数)。

    我建议您相信编译器是否应该内联函数。如果您确实想要内联代码,请考虑使用宏。

  • <强>开销

    使用函数时,内存开销最小,因为您不重复代码;内联代码重复到调用站点。这些天的性能开销可以忽略不计,因为现代架构只是非常良好的预测和调用,只有1-2个周期的开销。

答案 1 :(得分:3)

这取决于您的编译器设置及其优化代码的方式。一些函数是内联的。其他人不是。这通常取决于您是否针对大小或速度进行优化。

通常,调用函数会导致延迟,原因有两个:

  • 程序需要挂钩到功能代码启动的内存中的某个随机位置。为此,需要将当前光标位置保存到堆栈中,以便知道返回的位置。此过程消耗多个CPU周期。

  • 根据您的CPU架构,可能有一个管道,它将当前指令执行的内存中的下一条指令从内存中提取到CPU缓存中。这是为了加快执行速度。调用函数时,游标挂钩到一个完全不同的地址,所有缓存的指令都从管道中刷新。这会导致进一步的延误。

答案 2 :(得分:2)

函数可以是inlined,但是规范(大部分)是函数在特定地址,传递给函数的值放在堆栈上,然后将结果放在堆栈上并返回。

答案 3 :(得分:1)

如果某些条件得到满足,肯定可以内联函数,但它们肯定不会总是内联。通常,调用函数会产生真正的非内联函数调用。函数调用附加了一些额外费用,例如

  • 根据函数的调用约定准备函数的参数
  • 接收函数的返回值
  • 功能序言和结尾代码,负责本地内存管理,参数内存管理和寄存器值保存
  • 函数可以破坏一些CPU寄存器,从而破坏它们在调用代码中的使用,从而阻碍优化
  • 以非线性方式执行的代码的CPU缓存友好和虚拟内存友好行为

如果函数体嵌入到调用代码中,所有这些都会产生开销,可能不存在。