进程地址空间 页表
解释虚拟地址和写实拷贝的数据解耦问题
结构
- 对于每个进程的内核PCB结构来说,其中都存储了
进程地址空间
结构的地址。
什么叫进程地址空间?
进程地址空间,本质上是一个描述进程可用地址范围的大小。
进程地址空间存储着进程运行时所需要的数据的虚拟地址。经过页表映射才能访问到物理地址。
进程地址空间的作用
- 避免将所有数据直接记录到物理内存中,方便管理,让我们以统一结构的视角看待内存,即在虚拟内存中各个空间对应的地址有序固定,而实际映射的物理内存的位置并不固定。
进程地址空间的区域划分(mm_struct)
如上图所示,地址空间中存在各种各样的区域。我们通过记录每个区域的起始地址和结束地址,就可以将各个区域划分开来。
如果超过了规定的值,就称为越界。
页表
k-V
虚拟地址 | 物理地址 | 标志位 | 代码或者数据是否已经载入到内存 |
---|---|---|---|
0x123 | 0x321 | rw | 1 |
- rw:可读可写
- 1:已经被加载
例如:
CPU中,存在一个
cr3
寄存器(类似的还有cr2
),存储着当前进程的页目录(物理地址),并且在进程切换的时候,页表的地址也会被现场保护
。根据记录的虚拟地址找到物理地址。
页表的作用
权限管理——利用页表记录的标志位,可以检查内存操作是否违规。
例如:如果有一个变量位于常量区,那么它的标志位为r(只读),如果尝试w(写入)的时候,就会被阻拦。拦截越界如果在转换过程中内存出现了异常访问,直接进行拦截。从而这个请求不会抵达物理内存,从而保护物理内存。
页表的存储方式
假设现有一个地址 0000 0000 0000 0000 0000 0000 0000 0001
,在32位的x86架构下,这个地址会被分为三段:
- 10位:对应一级页表(页目录)中的页目录表项(PDE)。
- 10位:对应二级页表(页表)中的页表项(PTE)。
- 12位:对应页框内的偏移量。
分段详细解释
- 页目录表项(PDE):一级页表的10位用于索引页目录表项。页目录表项指向一个页表。
- 页表项(PTE):二级页表的10位用于索引页表项。页表项指向一个物理页框。
- 页框内的偏移量:最后的12位用于指定页框内的偏移量。一个页框的大小为4KB(2^12字节)。
页表的大小
一个进程中的页表大小的计算如下:
- 每个页目录(一级页表)包含1024个页目录表项,每个页目录表项指向一个页表。
- 每个页表(二级页表)包含1024个页表项,每个页表项指向一个物理页框。
由于每个页目录表项和页表项通常占用4字节:
- 一个页目录的大小:1024 * 4 = 4096字节 = 4KB。
- 一个页表的大小:1024 * 4 = 4096字节 = 4KB。
一个进程中的页表总大小:
- 页目录的大小 + 页表的大小总和。
- 在最坏情况下,假设每个页目录表项都指向一个页表,总共1024个页表,那么总大小为:
- 页目录:4KB
- 1024个页表:1024 * 4KB = 4MB
父子进程
- 子进程在创建时,也会基于父进程创建属于自己的页表和进程地址空间。
写实拷贝–操作系统自动完成的
当子程序有对数据进行修改,并且通过页表访问到的物理地址和父进程的地址是同一个的时候。
就调整子进程的页表,将重新分配一块区域并记录到子程序的页表中。
(注意,这里没有修改虚拟地址,所以父子进程的虚拟地址还可能相同)
惰性加载
运行一个程序时,并不会将它对应磁盘的数据都加入到内存中,而时分批加载。
并且,如果短期内不会使用的数据,并不会被加载到内存 —— 惰性加载。页表中会进行记录。
因此,我们在创建一个进程的时候,先创建内核数据结构,再加载对应的可执行程序。
总结:
进程地址空间和页表,实现了进程管理模块和内存管理模块的解耦。