Linux进程内存布局全解析
linux 进程 内存布局

首页 2024-12-12 05:05:30



Linux进程内存布局:深度解析与理解 在现代计算机系统中,进程是操作系统动态执行的基本单元

    每个进程都运行在一个属于它自己的内存沙盘中,这个沙盘就是虚拟内存(Virtual Memory)

    在Linux系统中,虚拟内存不仅简化了程序的编写,还提高了内存的使用效率

    本文将深入探讨Linux进程内存布局,帮助读者理解其工作原理和重要性

     一、虚拟内存与物理内存的映射 在编写程序时,我们使用的是虚拟内存布局,它是建立在真实的物理内存之上

    虚拟内存一般比物理内存要大,并且每个进程都享有独立的虚拟内存

    虚拟内存通过一些内存映射机制,被映射到真实的物理内存

    这种机制使得程序能够正常执行,即使只有部分地址空间在物理内存中

     虚拟内存的规划之一是将每个程序使用的内存切割成小型的、固定大小的“页”(page)单元

    相应地,将RAM划分成一系列与虚存页尺寸相同的页帧

    任一时刻,每个程序仅有部分页需要驻留在物理内存页帧中,这些页构成了所谓驻留集(resident set)

    程序未使用的页拷贝保存在交换区(swap area)内,这是磁盘空间中的保留区域,作为计算机RAM的补充,仅在需要时才会载入物理内存

     虚拟内存到物理内存的映射通过数据结构页表实现,内核为每个进程维护一张页表

    页表中的每个条目要么指出一个虚拟页面在RAM中的所在位置,要么表明其当前驻留在磁盘上

    若进程试图访问的地址并无页表条目与之对应,那么进程将收到一个SIGSEGV信号

     二、Linux进程内存布局详解 在32位的Linux系统中,进程的虚拟地址空间大小为4GB,其中低地址空间的3GB属于用户空间,高地址空间的1GB属于内核空间

    在用户空间的3GB中,又划分出多个区域:代码段、数据段、BSS段、堆段、内存映射区和栈段

     1.代码段(Text Segment) 代码段具有只读权限,用于存放可执行程序、字符串、只读变量等

    例如,定义的const变量、printf函数的格式化字符串等

    代码段的主要目的是防止进程通过错误指针意外修改自身指令,确保程序的稳定运行

     2.数据段(Data Segment) 数据段具有读写权限,用于存放初始值非0的全局变量、静态变量

    这些变量的数据会被存储在磁盘空间中,即存放在可执行文件中

     3.BSS段(Block Started by Symbol Segment) BSS段同样具有读写权限,用于存放初始值为0或未初始化的全局变量、静态变量

    这块内存会由操作系统初始化为0

    在程序启动之前,系统会将这些变量所在的内存区域全部初始化为0,而无需在编译阶段进行

     4.堆段(Heap Segment) 堆段是运行时可动态分配的内存段,向上生长,由用户进行申请和释放等管理操作

    堆段范围由两个指针进行限制:start_brk指针表示堆段的起始地址,brk指针表示堆段的结束地址

    堆段的扩张和收缩实际上都是通过移动brk指针来实现的

    当用户申请的内存小于128KB时,malloc会通过brk()从堆上申请内存;当用户申请的内存大于等于128KB时,malloc会通过mmap从内存映射区申请内存

     5.内存映射段(Memory-Mapped Segment) 内存映射段也称为文件映射区和匿名映射区,加载的动态库、打开的文件等均映射到该区域

    内存映射分为文件映射和匿名映射两种

    文件映射将文件映射到进程的虚拟地址空间中,而匿名映射则将物理内存映射到进程的虚拟地址空间,如进程间通信

     6.栈段(Stack Segment) 栈段用于存放非静态的局部变量、函数调用过程的栈帧信息等,地址空间向下生长,由编译器自动分配和释放

    栈帧中存储了函数的局部变量、实参和返回值

    栈的增长是从高地址向低地址增长的,即向堆的方向增长

    栈的大小在运行时由内核动态调整,栈动态增长后就