zoukankan      html  css  js  c++  java
  • 函数调用开销

    做了几个实验,简单学习了解一下函数调用的开销。
    程序1—没有参数的函数调用:
    [cpp] view plaincopyprint?
    #include <stdio.h>  
    void test() 

     return; 

    int main(int argc, char *argv[]) 

     test(); 
     return 0; 

     

    用gcc -S得到程序1的汇编代码:

    1.         .file   "test.c"  
    2.         .text  
    3. .globl test  
    4.         .type   test, @function  
    5. test:  
    6.         pushl   %ebp  
    7.         movl    %esp, %ebp  
    8.         nop  
    9.         popl    %ebp  
    10.         ret  
    11.         .size   test, .-test  
    12. .globl main  
    13.         .type   main, @function  
    14. main:  
    15.         pushl   %ebp  
    16.         movl    %esp, %ebp  
    17.         call    test  
    18.         movl    $0, %eax  
    19.         popl    %ebp  
    20.         ret  
    21.         .size   main, .-main  
    22.         .ident  "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"  
    23.         .section        .note.GNU-stack,"",@progbits  
     

    从上面汇编代码可以看出,对于没有参数函数调用的开销:
    1. 调用函数和返回,所以需要执行一次call/ret指令对。
    2. 函数内部,需要保护现场,所以需要把%ebp push到栈中,返回前,再pop出来。
    3. 构造函数运行环境,将%ebp赋值为当前的栈顶%esp。
    则没有参数函数调用开销是5个指令。
    程序2-带参数函数调用:

    1. #include <stdio.h>   
    2. void test(int a)  
    3. {  
    4.         (a)++;  
    5.         return;  
    6. }  
    7. int main(int argc, char *argv[])  
    8. {  
    9.         int a = 1;  
    10.         test(a);  
    11.         return 0;  
    12. }  
     

    用gcc -S得到程序2的汇编代码:

    1.         .file   "test.c"  
    2.         .text  
    3. .globl test  
    4.         .type   test, @function  
    5. test:  
    6.         pushl   %ebp  
    7.         movl    %esp, %ebp  
    8.         addl    $1, 8(%ebp)  
    9.         nop  
    10.         popl    %ebp  
    11.         ret  
    12.         .size   test, .-test  
    13. .globl main  
    14.         .type   main, @function  
    15. main:  
    16.         pushl   %ebp  
    17.         movl    %esp, %ebp  
    18.         subl    $20, %esp  
    19.         movl    $1, -4(%ebp)  
    20.         movl    -4(%ebp), %eax  
    21.         movl    %eax, (%esp)  
    22.         call    test  
    23.         movl    $0, %eax  
    24.         leave  
    25.         ret  
    26.         .size   main, .-main  
    27.         .ident  "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"  
    28.         .section        .note.GNU-stack,"",@progbits  
     

    相比于没有参数函数调用的开销,带参数函数调用多2个指令,用于传递参数:
    movl -4(%ebp), %eax
    movl %eax, (%ebp)
    每个参数的传递时都需要2个指令。
    而如果是指针参数,则函数在使用时,还得需要2个指令。
    这么看,函数调用的开销还挺大的。
    所以,当一个函数很小且调用频繁时,应该用宏或内联函数进行替代。
    另外,虽然函数调用有开销,但除非有特殊的必要,该用函数的地方还是应该使用函数,否则会严重降低代码的可读性和可维护性。

  • 相关阅读:
    spring AOP
    ElasticSearch RestHighLevelClient 通用操作
    JDK动态代理为什么必须针对接口
    Spring 中的统一异常处理
    ThreadPoolExecutor线程池解析与BlockingQueue的三种实现
    LinkedList源码解析(JDK8)
    MySQL表的四种分区类型
    Reids原理之IO模型
    缓存穿透和缓存雪崩问题
    uwsgi中processes和thread参数的影响大小
  • 原文地址:https://www.cnblogs.com/byfei/p/14104513.html
Copyright © 2011-2022 走看看