1、 指令、常量、变量的生命周期
1.1 什么是生命周期
生命周期,指的就是空间从诞生到消亡。
诞生:从内存中开辟出空间。
消亡:释放空间
只有在生命周期这段时间内,空间才是有效的,在生命周期外的时间,空间是无效的,不能访问。
1.2 指令和常量的生命周期
指令在.text中,常量要么在.text中,要么在.rodata中。
指令和常量的生命周期为整个程序运行期间,
疑问:为什么指令和常量的生命周期是整个程序运行期间?
就以指令为例来解释这个问题,假如在.text中,某些指令所占空间的生命周期不是整个程序运行期间的话,这就麻烦了,当程序运行到某个时间点需要调用某个函数时,结果函数指令所在空间因为生命周期到了而被释放了,调用这个函数时就会调用失败,整个程序运行出错。
1.3 .data、.bss变量的生命周期
全局变量和静态局部变量的存储类为.data或者.bss,所以.data、.bss变量指的就是全局变量和静态局部变量,.data、.bss变量的生命周期也为整个程序运行期间。
也就是说程序一开始运行时变量空间就存在,直到到整个程序运行结束.data和.bss被释放时,.data和.bss中的全局变量和静态局部变量才会被释放。
为什么.data、.bss变量的生命周期也为整个程序运行期间?
以全局变量为例,全局变量是所有函数共享操作的变量,如果运行到某个时刻被释放了,也就是生命周期到了,这也扯淡了,这会导致某个正在使用该全局变量的函数出现严重错误。
例子:
int i = 0; //i一直有效,直到程序运行结束 int fun() { static int fnum = 0; //fnum一直有效,直到程序结束,每次调用fun函数时,累加的都是同一个fnum printf("%d\n", fnum++); } int main(void) { for(i=0; i<5; i++) { fun(); } }
1.4 栈变量的生命周期
形参和自动局部变量的存储类为栈,所以栈变量指的就是形参和自动局部变量
定义形参和自动局部变量的代码,编译后会变成代码块的压栈、弹栈指令。
我们写一个伪代码
int fun(int a) { int b; ... if(a>100) { int c; ... } }
编译后伪代码
fun { push a //压栈,从栈中给a开辟空间 push b //压栈 ... if { push c //压栈 ... pop c //弹栈 } pop b //弹栈,释从栈中开辟的空间b pop a //弹栈,先压栈的后弹栈 }
栈变量的生命周期 = 从push指令开辟空间 到 pop指令释放空间 期间。
代码块开始运行时执行push,代码块运行结束时执行pop,因此栈变量的生命周期 约等于 代码块的生命周期。
例子:
int fun(int a) //a生命周期:代码块fun的生命周期 { int b; //b生命周期:代码块fun的生命周期 if(a > 100) { int c; //c生命周期:代码块if的生命周期 c = a + b; } { int d; //d生命周期:代码块的生命周期 d = 2*c; } }
疑问:register变量的生命周期?
认为与栈变量相同。
13.5 堆变量的生命周期
malloc成功后,堆变量的生命周期开始,调用free将空间释放后,生命周期结束。
所以堆变量的生命周期 == malloc 到 free之间的时间。
疑问:如果忘了free怎么办呢?
程序运行结束时整个堆会释放,堆中忘了free的堆变量空间自然也会被释放,但是一定要在程序运行时就free,不要等到程序运行结束再释放,至于为什么要这样,在第1章有详细解释。