进程内存空间
Linux中使用虚拟内存技术,将进程内存空间分为两部分:内核空间和用户空间。
----+------------------+
1G | | 内核空间(与其他进程共享)
----+------------------+
| |
3G | | 用户空间(进程私有)
| |
----+------------------+
内核空间是操作系统的私有空间,用户空间是进程的私有空间。运行在用户空间的进程不可以访问内核空间。C程序运行在用户空间中,根据内存分配方式,用户空间又分为以下几个区域。
+------------------+ 高地址
| ... | 参数和环境变量
+------------------+
| stack | 栈区 向下增长
+------------------+
| mmap | 内存映射区(动态链接库...)
+------------------+
| heap | 堆区 向上增长
+------------------+
| bss | 未初始化的全局变量
+------------------+
| data | 已初始化的全局变量
+------------------+
| rodata | 只读数据区
+------------------+
| text | 代码区
+------------------+ 低地址
栈区(局部变量)
局部变量和函数堆栈帧都在栈区,栈区向下增长,栈区的大小是固定的,一般为8M。
// a, b, c都是栈区的局部变量
int f(int a, int b) {
int c = a + b;
return c;
}
堆区
使用malloc
申请的变量在堆区,堆区向上增长,堆区的大小是不固定的,一般为1G。
// p是堆区的变量
int* p = (int*)malloc(sizeof(int) * 10);
全局变量
全局变量在data、bss、rodata区。其中data区存放已初始化的全局变量,bss区存放未初始化的全局变量,rodata区存放只读的全局变量。
static int x = 1; // data区 静态全局变量
int a = 1; // data区 全局变量
int b; // bss区 全局变量
const int c = 2; // rodata区 只读全局变量
int f() {
static int d = 3; // data区 静态局部变量
static int e; // bss区 静态局部变量
return 0;
}
生命周期
存储在不同位置的变量,其生命周期也不相同
存储位置 | 生命周期 |
---|---|
寄存器 | 由编译器决定 |
栈区 | 函数调用时创建,函数返回时销毁 |
堆区 | 由程序员决定 |
data区 | 程序启动时创建,程序结束时销毁 |
bss区 | 程序启动时创建,程序结束时销毁 |
rodata区 | 程序启动时创建,程序结束时销毁 |
text区 | 程序启动时创建,程序结束时销毁 |
作用域
全局变量和静态变量的作用域是整个文件,局部变量的作用域是函数内部。
计数器
int counter()
{
// count是局部静态变量,函数返回时不会销毁
static int count = 0; // data区
count++;
return count;
}
int main()
{
printf("%d\n", counter()); // 1
printf("%d\n", counter()); // 2
printf("%d\n", counter()); // 3
return 0;
}