进程虚拟地址空间内存划分和布局

进程虚拟地址空间内存划分和布局

对于任何的编程语言,产生的两种东西无非就是指令和数据。

比如在Windows上的xxx.exe文件,这个文件在磁盘上放着,运行的时候要加载到内存上去,当然不可能直接加载到物理内存上的。在x86体系32位的Linux系统上,系统会给当前进程分配一个2^32(4G)大小的一块空间,叫做进程的虚拟地址空间。

什么叫做虚拟地址空间?

有这么四句话很有名

1
2
3
4
它存在,你能看得见,它是物理的
它存在,你看不见,它是透明的
它不存在,你却看得见,它是虚拟的
它不存在,你也看不见,它被删除了

进程虚拟地址空间

从地址0x00000000​开始到0x08048000​这块区域是不能访问的

1
2
3
4
char *p=nullptr;
strlen(p);
char *src=nullptr;
strcpy(dest,src);//这两行代码程序直接崩溃

接下来从0x08048000开始,存放的是​.text段(指令存放的位置)。.rodata​段(只读数据段)例如​char *p=”hello world”; *p=’a‘​,这个是不允许的。这两个段都是只能读不能写的。

接下来是.data段和​.bss​段,​.data段存放的是初始化的并且初始化不为0的,​.bss​段存放的是未初始化和初始化为0的数据。

接下来是.heap​堆区。刚开始是空的,只有调用​new​或者​malloc才会有空间。

接下来是加载共享库,*.dll *so​。

接下来是stack​区,存放局部变量,不过栈区从下往上进行增长的。而堆是从高地址到低地址进行的。

接下来是命令行参数和环境变量。

上述存在于0x08048000​到​0xc0000000​这3G的用户空间中。

下面还有1G的空间是内核空间,主要是这几种

1
2
3
ZONE_DMA
ZONE_NORMAL
ZONE_HIGHMEN

看看下面这些代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int gdata1=10;//data段
int gdata2=0;//bss段
int gdata3;//bss段
static int gdata4=1;//data段
static int gatda5=0;//bss段
static int gdata6;//bss段
int main()
{
int a=12;//这三个不生成符号,对应的是指令,在.text段
int b=0; //运行时,指令在栈上开辟4字节的空间,不是存在栈上
int c;

static int e=13;//data段
static int f=0;//bss段
static int g;//bss段

cout<<c<<g<<endl;
return 0;
}

每一个进程的用户空间的私有的,内核空间是共有的。