您的位置:首页 > 运维架构 > Linux

Linux进程内存布局

2018-03-30 13:41 519 查看
下图是一张32位x86架构上运行的Linux中进程标准的内存段布局, 通过该图从上至下的简要分析Linux中进程的内存分布情况和各自的大致用途:



内核空间和用户空间

对于32位X86架构上运行的Linux而言, 其虚拟地址空间的寻址范围从0 ~ 4G,内核将这块空间划分为两个部分,将最高的1G字节
0xC0000000 ~ 0xFFFFFFFF
称为“内核空间”, 顾名思义是提供给内核使用;而将较低3G字节
0x00000000 ~ 0xBFFFFFFF
称为“用户空间”,即提供给各个运行的进程使用。

理论上,每个进程都是可以访问全部能寻址的4G虚拟内存空间的,但是系统为了防止内核空间被用户进程有意或无意的破坏,所以采用了分级保护措施: 将内核定为0级,将用户进程定为3级, 这样用户进程便无法直接访问内核的虚拟内存空间,仅能通过系统调用来进入内核态,从而来访问被限定的部分内核空间地址。同时,由于访问权限的机制,不同的进程间也都拥有独立的用户空间。这样非对称的访问机制使得Linux系统运行更加的安全稳定。

PS: 每个进程都运行在一个属于自己的内存沙盒里, 这个沙盒即虚拟地址空间,这些虚拟地址再通过页表(page table)来映射到物理内存上, 页表由操作系统维护并被CPU所引用。所以用户空间地址的映射是动态变化的;而内核空间则是持续存在的,在每个进程中都映射到相同的物理内存中,这样便于寻址以应对随时出现的中断和系统调用。

另外,用户进程也是无法访问
0x00000000 ~ 0x08048000
这一段虚拟内存地址的
,在这段地址上有诸多例如C库,动态加载器如ld.so和VDSO等的映射地址。 如果用户进程访问到该区间会返回段错误。

用户空间内存布局

用户空间中最顶部的段叫做栈,他被用于存放函数参数和动态局部变量。调用一个方法或函数会将一个新的栈帧(stack frame)压入到栈中,这个栈帧会在函数返回时被清理掉。在运行过程中,进程通过函数的调用和返回使得控制权在各个函数间转移,在新函数调用时,原函数的栈帧状态保持不变,并为新的函数开辟其所需的帧空间;当调用函数返回时,该函数的运行空间随着栈帧被弹出而清空,这次进程回到原函数的栈帧环境中继续执行。进程中的每一个线程都有属于自己的栈

通过不断向栈中压入数据,超出其容量就会耗尽栈所对应的内存区域,这将触发一个页故障(page fault),而被Linux的
expand_stack()
处理,它会调用
acct_stack_growth()
来检查是否还有合适的地方用于栈的增长。如果栈的大小低于
RLIMIT_STACK
(通常为8MB),那么一般情况下栈会被加长,程序继续执行,感觉不到发生了什么事情。这是一种将栈扩展到所需大小的常规机制。然而,如果达到了最大栈空间的大小,就会栈溢出(stack overflow),程序收到一个段错误(segmentation fault)。

注: 动态栈增长是唯一一种访问未映射内存区域而被允许的情形,其他任何对未映射内存区域的访问都会触发页错误,从而导致段错误。一些被映射的区域是只读的,因此企图写这些区域也会导致段错误。

mmap

在栈段的低一段便是mmap端,mmap是一种高效便捷的文件I/O方式,内核将文件内容映射在此段内存中,常见情形便是加载动态链接库。另外,在Linux中,如果你通过
malloc
申请一块大于
MMAP_THRESHOLD
(通常默认为128KB, 可用
mallopt()
修改)大小的堆空间时, glibc会返回一块匿名的mmap内存块而非一块堆内存。

在mmap段下面便是堆段了,堆段同栈段一样,都是为进程运行提供动态的内存分配,但是其和栈的区别在于堆上内存的生命期和执行分配的函数的生命期不一致,堆上分配的内存只有在对应进程通过系统调用主动释放或进程结束后才会释放。所以,内存泄露这个经典的问题便由此产生。

另外, 由于堆内存的反复申请和释放,也不可避免的会造成堆段碎片化。这种情况可以使用“对象池”的设计手段来避免。



堆段再往下便是BSS段DATA段这两个静态内存区域,这两段都是用来存储静态局部或静态全局变量,其在编译期间便决定了虚拟内存的消耗。区别是DATA段存放的是已经初始化的变量,其映射自程序镜像中包含对应静态变量的文件;而BSS段则存放的是未初始化的变量,他不映射自任何一个执行文件。根据C语言标准规定,未初始化的静态成员变量的初始值必须为0,所以内核在加载二进制文件后执行程序前会将BSS段清0。

BSS和DATA段下是代码段(TEXT),这段中存有程序的指令代码。Text段是通过只读的方式加载到内存中的,他在多个进程中是可以被安全共享的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 内存