本帖最后由 heimaojingzhang 于 2018-8-18 14:09 编辑
C 程序的内存空间布局
表格中, 从上到下为高地址到低地址方向
segment 含义
argument and environment 命令行参数和环境变量(环境表和环境字符串)
stack 栈
heap 堆
bss 未初始化数据段
data 初始化数据段
text 正文段
1. 自由存储区: C++中, 堆是由 new 和 delete 管理的, 自由存储区(free store)是由 malloc 和 free 管理的
2. 全局区: C++中, 使用全局区(静态区)存储全局变量和静态变量, 不再区分data和bss, 即初始化和未初始化的数据占用同一块内存
3. 常量区: 存储字符串常量, 正常手段不允许修改, 和上面表格中的地址不连续存放, 所以单独说?
4. 立即数: 对于整数类型, 如果初始化常量值出现在表达式语句中, 通常会成为立即数, 被包含在生成的代码中, 即数字常量占用代码段汇编指令的操作数部分?
5. 全局区的初始化常量值: 没有参与代码生成的常量,比如用于全局变量的初始化、数组声明、模板参数等等,哪里也不存,在编译期就处理了
1. 命令行参数和环境变量
使程序了解进程环境,在执行时分配内存
在 shell 中执行某个程序(shell 的子进程)时,shell 进程调用 exec 函数将命令行参数传递给要执行的程序
2. 栈
存储自动变量, 函数调用者信息, 包括函数参数(可变参数列表的压栈方向是从右向左), 函数内局部变量, 函数返回值, 函数调用时的返回地址
执行流执行到函数调用时分配内存, 高地址是栈底, 向低地址方向增长
函数返回时, 系统自动回收内存
3. 堆
用于动态分配的内存, 需要手动管理内存
执行流执行到手动分配内存函数调用(如 malloc 或 new)时, 分配内存
4. bss 段
Block Started by Symbol, 即以符号开始的内存块
未初始化的数据可能是全局变量, 静态变量
bss 段并不占用可执行程序的镜像的空间,而是在执行时分配内存,并由 exec 函数初始化为0, 例如声明全局数组 int array[100], 不会将100个0记录在可执行文件镜像中,而只是记录了标识符a和其所占用的内存大小
变量的大小记录在符号表中,要分配的整个 bss 段的大小记录在段表(Section headers)中
5. data 段
具有明确初始值的全局变量和静态变量
存在于程序镜像文件中,由 exec 函数从程序镜像文件中读入内存
6. text 段
CPU 执行的机器指令
父进程和子进程之间可共享正文段
存在于程序镜像文件中且只读, 由 exec 函数从程序镜像文件中读入内存, 例如在 shell 中正在执行的程序运行正文段的指令
举例
int a = 0; // a 在 data
char *p1; // p1 在 bss
main()
{
int b; // b 在 stack
char s[] = "abc"; // s 在 stack, abc\0 在常量区
char *p2; // p2 在 stack
char *p3 = "123456"; // p3 在 stack, 123456\0 在常量区
static int c = 0; // c 在 data
p1 = (char *)malloc(10); // 申请的10字节内存在 heap, bss中的指针指向heap中的内存
p2 = (char *)malloc(20); // 申请的20字节内存在 heap, stack中的指针指向heap中的内存
strcpy(p1, "123456"); // 123456\0 在常量区,编译器可能会将它与 p3 所指向的 "123456" 优化成一块
}
文件映射区
进程将文件从硬盘读取到文件映射区,以后在内存操作文件
内核映射区
操作系统的内核程序映射到这个区域 |