虚拟地址空间的分配与系统环境有关: 下图为linux X86环境

虚拟地址 在这里插入图片描述

*1.保留区(受保护的地址)

保留区即为受保护的地址,大小为0~4K,位于虚拟地址空间的最低部分,未赋予物理地址(不会与内存地址相对应,因此其不会放任何内容)。 任何对它的引用都是非法的,用于捕捉使用空指针和小整型值指针引用内存的异常情况。大多数操作系统中,极小****的地址通常都是不允许访问的,如NULL。

C语言将无效指针赋值为0也是出于这种考虑,因为0地址上正常情况下不会存放有效的可访问数据。将指针赋值为0,意味着该指针将永远不会被使用, 从而不会出现野指针情况。 #define NULL 0 与 #define NULL (void)0 在C语言中是等效的,而在C++中 ,只能 用#define NULL 0,后面 #define NULL (void)0的使用会出错。**

2.代码段

代码段也称正文段或文本段,通常用于存放程序执行代码(即CPU执行的机器指令)。一般C语言执行语句都编译成机器代码保存在代码段。通常代码段是可共享的,因此频繁执行的程序只需要在内存中拥有一份拷贝即可。代码段通常属于只读,以防止其他程序意外地修改其指令(对该段的写操作将导致段错误)。某些架构也允许代码段为可写,即允许修改程序。

3.数据段(.data段)

数据段通常用于存放程序中已初始化的全局变量和静态局部变量。数据段属于静态内存分配(静态存储区),可读可写。由于全局变量未初始化时,其默认值为0,因此值为0的全局变量位于.bbs段(不位于数据段)。对于未初始化的局部变量,其值是不可预测的。注意:在代码段和数据段之间还包括其它段:只读数据段和符号段等。

4..bbs段

该段用于存放未初始化的全局变量和静态局部变量,包括值为0的全局变量。 数据段和.bbs段又称为全局数据区,前者初始化,后者未初始化。 ELF段包括:代码段、其它段(只读数据段和符号段等)、.data段(数据段)和.bbs段,都属于可执行程序部分。

5.堆空间

new( )和malloc( )函数分配的空间就属于对空间,用于内存空间的分配,其从下往上。 堆用于存放进程运行时动态分配的内存段,可动态扩张或缩减。堆中内容是匿名的,不能按名字直接访问,只能通过指针间接访问。当进程调用malloc(C) 和new (C++)等函数分配内存时,新分配的内存动态添加到堆上(扩张);当调用free(C)/delete(C++)等函数释放内存时,被释放的内存从堆中剔除(缩减) 。

6.内存映射段(共享库)

此处,内核将硬盘文件的内容直接映射到内存, 任何应用程序都可通过Linux的mmap()系统调用请求这种映射。内存映射是一种方便高效的文件I/O方式, 因而被用于装载动态共享库。如C标准库函数(fread、fwrite、fopen等)和Linux系统I/O函数,它们都是动态库函数,其中C标准库函数都被封装在了/lib/libc.so库文件中,都是二进制文件。这些动态库函数都是与位置无关的代码,即每次被加载进入内存映射区时的位置都是不一样的,因此使用的是其本身的逻辑地址,经过变换成线性地址(虚拟地址),然后再映射到内存。而静态库不一样,由于静态库被链接到可执行文件中,因此其位于代码段,每次在地址空间中的位置都是固定的

7.栈空间

用于存放局部变量(非静态局部变量,C语言称为自动变量),分配存储空间时从上往下。栈和堆都是后进先出的数据结构。

8.命令行参数

该段用于存放命令行参数的内容:argc和argv。

9.环境变量

用于存放当前的环境变量,在Linux中用env命令可以查看其值。

10.虚拟地址空间的作用(好处)

1.方面编译器和操作系统安排程序的地址;2.方便实现各个进程空间之间的隔离,互不干扰,因为每个进程都对应自己的虚拟地址空间;3.实现虚拟存储,从逻辑上扩大了内存。

补充内容:

代码段(.text段)与只读数据段和符号段(.rodata段),都属于只能读的部分,在链接的时候这两部分会链接成为一个整体;而.data段和.bbs段属于可读可写RW的部分。这四个部分都是以页(每页4KB)的形式存放在内存中。进程控制块PCB(又叫进程描述符)放于内核空间。

转载自:https://blog.csdn.net/qq_33883085/article/details/88430087