一个可执行文件被加载到内存中执行: =>成为一个运行的程序【进程】
内存分配:
使用虚拟的内存地址(线性地址),os负责把虚拟内存映射到物理内存。
保护模式(进程不直接使用物理内存)提供内存分页机制,例如32位系统下,物理内存每4KB为一页,虚拟内存到物理内存以页为单位映射。
os会以链表的形式记录各个进程的控制信息,在Windows中称为进程控制块PCB,在llinux中对应task_struct结构体。
不管是使用哪种数据结构存储,每个进程的控制信息中都有一个指针,存储的是当前进程页目录的物理地址。页目录也是一个内存页,其中每一个条目都是一个指针,指向用来存储物理内存页起始地址的页表。
32位系统下一个物理地址占4字节,4KB/4B=1K=1024,即1个页目录可以寻址1024个页表,1个页表可以寻址1024个物理内存页。
1024 * 1024 * 4KB = 4GB => 32位下这样的两级页表足够寻址4GB大小的内存空间
每个页面大小都是4K,所以内存页的起始地址一定是4K的整数倍,故页表中每一项的低12位一定是零。因此页表里每一条记录都有12位的空闲空间可以使用,它们可以用来标识对应物理内存页是否可读、可写、可执行等信息,其中就有一位用于标识该物理内存眼是否已经映射。因为进程向操作系统申请映射内存时,通常不会一申请就立马分配,操作系统会先记个账。例如Linux中,通过进程对应的task struct可以找到记录内存分配的链表。每个链表项都是一个Virtual Memory Area结构体,里面记录了进程已经申请的一段连续内存地址区间。但是真正的映射要到进程访问这段内存时才会进行。【使用必须先映射】
CPU在执行进程代码时拿到的也是线性地址(虚拟内存地址),线性地址到物理地址的转换交由CPU中的内存管理单元MMU负责。