一、程序从加载到运行中内存空间的使用情况
以linux系统上一个典型的c程序(如./a.out)为例,从shell执行到进程退出,详细分解匿名内存的分配、管理、销毁全过程。
1、shell调用fork()创建子进程
- shell调用fork()系统调用,内核复制shell的进程描述符(task_truct)及页表,创建出一个几乎完全相同的子进程。
- 内存分配:内核为子进程分配新的mm_struct(内存描述符)和新的页表。此时父子进程的虚拟地址空间指向相同的物理页,且这些也被标记为只读(写时复制)。
- 匿名内存初始状态:子进程继承了shell的匿名内存(如shell的堆和栈)。但随后子进程会立即执行execve,这些旧的匿名内存将被完全替换,所以它们没有实际意义。
2、子进程调用execve()加载新程序
execve系统调用负责将新的可执行文件加载到当前程序的地址空间,丢弃原有的所有内存映射,建立权限的虚拟地址空间布局。
①、内核读取可执行文件头(如elf) - 参与者:内核(fs/exec.c)中的do_execve系列函数)。
- 动作:解析elf文件头,识别代码段(.text)、数据段(.data)、只读数据段(.rodate)、bss段等。
②、建立虚拟内存区域(vma)
内核为程序的每个段创建一个vm_area_struct(vma)结构,描述该段在虚拟地址空间按中的起始地址、大小、权限(读/写/执行)和后备存储信息。
| 段类型 | 后备存储 | 是否匿名 |
|---|