总体布局
在32位系统中,linux进程的虚拟地址空间布局如下:
进程虚拟地址空间为 0x0 ~ 0xFFFFFFFF,一共4G大小。其中低位的3G为用户空间,高位的1G为内核空间。空间的各个部分为:
保留区
它并不是一个单一的内存区域,而是对地址空间中受到操作系统保护而禁止用户进程访问的地址区域的总称。大多数操作系统中,极小的地址通常都是不允许访问的,如NULL。C语言将无效指针赋值为0也是出于这种考虑,因为0地址上正常情况下不会存放有效的可访问数据。
代码和只读数据区
这一部分,只能读,不能写。代码、常量字符串、#define定义的常量存放在这。
数据段
保存全局变量、静态变量。可执行文件中的数据被映射至该区,包括.data和.bss。
堆
代码和数据区往上是运行时堆。从下往上增长。与代码/数据段在程序加载时就确定了大小不同,堆可以在运行时动态扩展或收缩。调用如malloc/free、new/delete这样的库函数时,操作的内存区域就在堆中。堆的范围通常较大,如在32位Linux系统中,堆的上限理论值可以达到2.9GB。堆顶的位置可通过函数brk和sbrk进行动态调整。
文件映射区
动态库、共享内存等映射物理空间的内存,一般是mmap函数所分配的虚拟地址空间。该区域用于映射可执行文件用到的动态链接库。在Linux 2.4版本中,若可执行文件依赖共享库,则系统会为这些动态库在从0x40000000开始的地址分配相应空间,并在程序装载时将其载入到该空间。在Linux 2.6内核中,共享库的起始地址被往上移动至更靠近栈区的位置
栈
栈用于维护函数调用的上下文,编译器用栈来实现函数调用。跟堆一样,用户栈在程序运行期间可以动态扩展和收缩。与堆相比,栈通常较小,典型值为数8MB。从上往下增长。
内核空间
内核总是驻留在内存中,是操作系统的一部分。内核空间就是为内核保留的,不允许应用程序读写这个区域的内容或直接调用内核代码定义的函数。