4G虚拟地址空间布局

4G虚拟地址空间布局

 

 

4G的虚拟内存空间:

其中1G是属于内核空间,另外的3G属于用户空间

所有的进程都拥有属于自己的用户空间,但却共享一个内核空间

 

现在我们从上向下开始分析

首先是用户空间:

①:128M大小的不可访问区域(保留区)

我们通常将申请的临时指针变量初始化时置为NULL,可以防止后续无意使用这个指针出错,因为NULL == 0x0,将其指针指向0x0这个地址时,因为0x0这个地址属于保留区,没有访问权限的。

②:.text代码段

这个区域存储的是代码中的指令。

指令:一份代码是由数据和指令构成的,除数据外剩下的都叫做指令,另外,局部变量也属于指令,但是局部变量存储在栈上,代码运行时才在栈中预留好的区域中开辟。

 

③:.data数据段

这个区域存储的是代码中的各种数据,包括全局变量,静态局部变量,但两者必须为已初始化且初始化不为零的数据

 

④:.bss段

这个区域存储也是代码中的各种数据,不过存储的是未初始化或者是初始化了但是为零的数据。

这个段其实在可执行文件中不占空间,(.bss段)在段表中保存着,因为它记录的都是一些未初始化的值要不就是初始化了但是为零的值,我们可以只记录符号和符号所要占用的大小,在程序运行时,才进行开辟并将其空间全部清零。可以用readelf -S或者objdump -h 查看

 

⑤:堆

当我们需要申请一块连续且指定大小的内存块的动态内存时,需要在堆中申请。需要手动申请,手动释放。不释放会造成内存泄漏。

 

⑥:栈

所有局部变量存储在这里,且函数的运行也需要栈的开辟,不过空间释放由系统完成。

 

⑦:命令行参数

int main()

{

//这是我们平常写的main函数

}

其实它长这样

int main(int argc, char *argv[],char *envp[])

{

//这是真实的main函数

}

 

前两个参数大家都很熟悉,argc是命令行参数的个数,不指定时默认为1,是当前文件名,char *argv[] 也可以写成char **argv,其中argv[0]默认保存的就是argc == 1时的程序名。如果在执行程序时后面跟随指令,则argc的值和argv[]中的元素就会发生变化。

然而这第三个参数是什么意思呢?在我们调用一些系统库函数的时候,我们需要使用预处理指令#include。但是我们系统怎么知道去哪个路径寻找这些头文件的函数定义呢?就是通过char *envp[](环境变量)来实现的。

 

话说回来,命令行参数就是我们的argv了。里面存放着我们的程序名,以及参数(如果你给了的话)。

⑧:环境变量

就是在第⑦条中介绍的,main函数的第三个参数。

 

 

 

我们再来看一下内核空间:

①:内存直接访问(ZONE_DMA(大约16MB)

全名ZONE_DirectMemoryAccess(直接内存访问),可以加快磁盘和内存之间数据的交换,不需要经过CPU的寄存器,这时CPU可以去干别的事,大大增加了效率。

 

②:ZONE_NORMAL (大约892MB)

内核中最重要最常用的部分。用于直接映射。PCB就在这里。

③:ZONE_HIGHMEM (128MB)

所谓的高端内存,用于在内核中映射高于1G的物理内存时使用。64位系统则没有该段(根本不需要,因为64位操作系统给内核空间分配的内存达到512G)。

猜你喜欢

转载自blog.csdn.net/IT_Quanwudi/article/details/84041163