虚拟地址的分配:
Linux:用户空间:内核空间 = 3:1
windows:用户空间:内核空间 = 2:2(虚拟地址低空间,即从0x00000000~0X7FFFFFFF的2GB为用户空间,而高地址0x80000000~0xFFFFFFFF被分配给了系统内核。)
图下研究的为Linux下的4G虚拟空间
接下来我们从上至下依次解释一下这些:
3G用户空间:
1、保留区
保留区128M,我们通常将申请的临时指针变量初始化时置为NULL,可以防止后续无意使用这个指针出错,因为NULL == 0x0,将其指针指向0x0这个地址时,因为0x0这个地址属于保留区,没有访问权限的。
2、.text段
指令段:通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
3、.data段
数据段(data segment)通常是指用来存放程序中已始化且不为0的全局变量和静态变量的一块内存区域。数据段属于静态内存分配。常量也放在这个区域。
4、.bss段
数据段:(Bss Segment)通常是指用来存放程序中未初始化或者初始化为0的全局变量的一块内存区域,在程序载入时由内核清0。bss段属于静态内存分配。
PS:.data段与.bss段的区别(为什么有两个数据段)
1) BSS段不占用物理文件尺寸,但占用内存空间;数据段占用物理文件,也占用内存空间。所以有两个数据段节省文件空间。
对于大型数组如int ar0[10000] = {1, 2, 3, ...}和int ar1[10000],ar1放在BSS段,只记录共有10000*4个字节需要初始化为0,而不是像ar0那样记录每个数据1、2、3...,此时BSS为目标文件所节省的磁盘空间相当可观。
2) 当程序读取数据段的数据时,系统会出发缺页故障,从而分配相应的物理内存;当程序读取BSS段的数据时,内核会将其转到一个全零页面,不会发生缺页故障,也不会为其分配相应的物理内存。
5、heap
堆:一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收
保存函数内部动态分配内存,是另外一种用来保存程序信息的数据结构,更准确的说是保存程序的动态变量。堆是“先进先出”数据结构。它只允许在堆的一端插入数据,在另一端移走数据。堆的地址空间“向上增加”,即当堆上保存的数据越多,堆的地址就越高。
6、共享库
在编写程序时,会依靠其他人已经写好的许多代码来执行例程或特殊功能。 这些代码存储在共享库中使用它们,需要将它们与自己的代码相链接,无论是在构建程序时还是在运行程序时。
7、stack
栈:栈(stack)
栈,由编译器自动分配释放,行为类似数据结构中的栈(先进后出)。
堆栈主要有三个用途:
①函数的返回地址(以便从被调用者返回)和参数
②临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量
③保存上下文:包括在函数调用前后需要保持不变的寄存器
8、命令行参数
C语言中有关命令行参数涉及到程序的主函数main(int argc,char *argv[])这样两个参数,其中,int argc表示命令行参数的个数(包括可执行程序名本身),char *argv[]表示每个参数的具体内容,argv[0]为命令行中可执行程序名本身,argv[1]为命令行中第二个参数的内容,依次类推。
9、环境变量
例:int execve(char *pathname,char* argv[],char*envp[]) ,char*envp就是所谓的环境变量
环变量是一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。许多用户(特别是那些刚接触Linux的新手)发现这些变量有些怪异或者难以控制。其实,这是个误会:通过使用环境变量,你可以很容易的修改一个牵涉到一个或多个应用程序的配置信息。
内核空间:
作用:Linux 操作系统和驱动程序运行在内核空间
物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系,注意内核的虚拟地址在“高端”,但是ta映射的物理内存地址在低端。
内核内存分配:
在x86结构中,三种类型的区域(从3G开始计算)如下:
ZONE_DMA 16MB
ZONE_NORMAL 892MB
ZONE_HIGHMEM 128MB