Reference
上述函数的调用过程其实解释了静态变量和局部变量的分配过程。而关于动态内存的分配过程是使用malloc,参考以下文章:
关联阅读:
程序执行大致过程
程序被编译成二进制代码后放入硬盘。当程序执行时,将代码调入内存,放入内存的代码段。同时程序中的变量也会按变量类型在对应的内存段中分配内存。然后CPU会从代码段取出每一条指令进行执行。CPU在执行一条指令时,从指令中取出的是相对地址,需要经过寻址方式确定最终的逻辑地址。有了逻辑地址再经过地址映射找到逻辑地址对应的物理地址。那么问题是当被代码调入内存后,是什么时候为这个程序进行的内存分配?又是以什么样方式进行内存分配的?
网上找到的答案如下:当执行这个EXE文件以后,此程序就被加载到内存中,成为进程。此时一开始程序会初始化一些全局对象,然后找到入口函数(main函数),就开始按程序的执行语句开始执行。此时需要的内存只能在程序的堆上进行动态增加/释放了。
根据解答,静态变量是在调用内存后,进程正真执行之前,在内存中为静态变量分配了内存,并且给了初始值。那么为静态变量分配到底是以什么样的方式分配的?操作系统是怎么知道要为这个程序的静态变量分配多大内存的?可能对应编译原理运行存储分配之静态存储分配。
至于在程序中动态申请的变量,是需要在程序执行具体的指令时才能去堆上进行申请。问题是当我们拿到这个动态内存的地址执行运算指令时,动态申请内存的动作已经完成了。接下来只是进行逻辑地址和物理地址的映射。那到底是什么时候在堆上申请的动态内存?以什么样的方式完成的申请?又是什么时候完成的地址映射?可能对应编译原理运行存储分配之动态存储分配。
理解整个过程的方式:写一个包含全局区、堆区、栈区、常量区的程序。然后直接看汇编代码,看一下每个变量的地址汇编后到底是怎么样表示的。
编译时不分配内存,只是根据声明时的类型进行占位。到程序执行时分配内存。
函数调用大致过程
- 首先内存中此时的画面是:sp和bp指向\_start函数的栈帧空间的对应位置。start调用main函数时,start要在自己的栈帧中保存自己下一条指令的地址。然后sp先++(从现在开始是main函数的栈帧),指向一片空内存,然后分配空间,把start函数的bp保存。然后把bp移动到sp的位置。
- 指令main函数的指令,为mian函数中的变量分配内存。
- 当main函数调用callee函数,为callee的实参分配内存。最后保存一下main下一条指令的地址。
- 然后sp先++(从现在开始是callee函数的栈帧),指向一片空内存,然后分配空间,把 main函数的bp保存。然后把bp移动到sp的位置。指令callee函数的指令,为callee函数中的变量分配内存。
- callee执行结束,释放callee函数的栈帧。
- 然后在main的栈帧中取出栈帧函数指令的地址放入pc,继续执行main函数,main可以从寄存器中获取返回值。
- main执行结束,释放main函数的栈帧。
- 然后在start的栈帧中取出栈帧函数指令的地址放入pc,继续执行 \_start函数。start可以从寄存器中获取返回值。
要点:
mian函数栈帧的开始位置存的是 start函数的bp,栈帧的结束位置存的是mian函数的下一条指令的地址。 即:对一个函数的栈帧而言,存调用者的bp,存自己的指令的地址。