参考:
主要参考这篇 内存中的堆和栈到底是什么
1.可执行文件
程序在运行前以可执行文件的形式存储在磁盘中。
典型的ELF可执行文件.jpg
在众多表项中我们重点关注:.text,.reload,.data,.bss这四个小段(节)
只读存储器段(代码段):
.text:存放已编译程序段机器代码。
.reload: 存放只读数据,如字符串和开关语句的跳转表。
读写存储器段(数据段):
.data:已初始化的全局C变量。
.bss:未初始化的全局C变量。(它在目标文件中不占据实际空间,目标文件格式区分初始化和未初始化变量是为了空间效率)
另外:1.标记有static静态标志的局部变量不在栈中管理,而是根据有无初始化,在.data或者.bss中。2.对于GCC编译器,初始化为0的变量存储在.bss中。
2.加载可执行文件
可执行文件在内存中运行时,有一个运行时存储器印象。
运行时存储器映像.jpg
- 代码段总是从地址0x08048000处开始。
- 数据段在接下来的下一个4KB对齐的地址处。
- 运行时堆在数据段之后接下来的第一个4KB对齐的地址处,并通过malloc库往上(高地址方向)增长。
- 中间还有一个段是为共享库(shared library)保留的。
- 用户栈总是从最大的合法用户地址开始,向下增长(低地址方向),通过esp栈指针进行push 和pop操作。
- 当程序开始运行时,加载器在可执行文件中段头部表的指引下,将可执行文件的相关内容拷贝到代码段和数据段。
3. 堆
动态存储器分配维护着一个进程的虚拟存储器区域,称为堆(heap)。
分配器将堆视为一组不同大小的块(block)的集合来维护,需要我们手动申请和释放。
堆可以分配更大的空间,但开销也会更多。
4.栈
栈由系统管理,用于局部变量的分配和释放,经常用来存储局部变量,函数参数,上下文环境等。
栈是一个后进先出(LIFO)结构,栈顶由堆栈指针寄存器ESP来标记。
栈顶是朝着低内存方向增长的,栈的大小需要有一定的限制。
5.测试题
#include <stdio.h>
int a = 0; //全局初始化区,数据段的 .data
char *p1; //全局未初始化区 数据段的 .bss
int main()
{
int b; //栈
char *p2; //栈
char s[] = "abc"; //栈
char *p3 = "123456"; // 123456\0 在代码段的.rodata,p3在栈上
p1 = (char *)malloc(10); //堆
p2 = (char *)malloc(20); //堆
static int c =0; //静态变量,在数据段的.data(已经初始化)
static int arr1[1000] = {233};// 静态数组,在数据段的.data(已经初始化)
static int arr2[1000]; //静态数组,在数据段的.bss(未初始化)
return 0;
}
网友评论