进程虚拟地址空间
如上图所示,进程的虚拟地址空间被统一划分成了多个固定区域,例如代码区,数据区,堆区,共享区,栈区,内核区。
代码区和数据区域:来自于可执行文件,代码区和数据区挨着,代码区总是在0x0040000地址以上,0x0040000地址以下另有它用。
运行时堆区域:它初始化大小为0,随着动态分配内存(malloc),运行时堆不断往高地址方向扩展,有个指针brk指向了堆的最高地址。
共享库的内存映射区域:这个区域是一些标准的系统库,这个共享库在物理内存中只存储一份,每个进程将这个区域的虚拟地址映射到同一份共享库物理内存上。
用户栈区域:这个区域紧挨着内核区域,处于高地址处,随着用户栈的出栈,入栈,动态扩展,入栈向低地址方向扩展,出栈则向高地址方向收缩,栈顶指针存储在栈寄存器(ESP)中。
内核区域:这个区域是操作系统自己代码,数据,栈空间,内核在物理内存中只存储一份,每个进程将这个区域的虚拟地址映射到同一份内核物理内存上。
内核和共享库的映射
3.什么是虚拟页,物理页?现代操作操作和CPU将物理内存按照固定的页大小分成很多份,每一份叫做物理页(PP),每一份有一个编号叫做物理页号(PPN),这个物理页大小通常是4KB,例如一个物理内存大小为20KB,这个物理内存可以分成5个物理页,那么物理页号(PPN)就是0,1,2,3,4。
虚拟内存也一样,它的页大小与物理内存的页大小相同,虚拟内存也被分成了很多份,每一份叫做虚拟页(VP),每一份的编号叫做虚拟页号(VPN),例如假设虚拟页大小为4KB,一个虚拟内存大小为10KB,这个虚拟内存可以分成2个虚拟页(VP),虚拟页号(VPN)就是0,1
每个物理页存储在物理内存上,每个虚拟页存储在磁盘上,如下图所示
虚拟内存和物理内存
上图的虚拟内存有8个虚拟页,物理内存有6个物理内存页,虚拟页存储在磁盘上,物理页则存储在DRARM上。
每个虚拟页可以有三种状态,未分配,已缓冲,未缓冲
未分配:虚拟页还没有分配磁盘空间
已缓冲:虚拟页缓冲或者映射在了物理页上。
未缓冲:虚拟页分配了磁盘空间,但没有在物理页上缓冲。
通常操作系统加载可执行文件后,创建了一个进程,这个进程就有了虚拟地址空间,这并不意味着可执行文件已经从磁盘加载到内存中了,操作系统只是为了进程虚拟地址空间的每个区域分配了虚拟页。
代码和数据区域的虚拟页被分配到了可执行文件的适当位置,此时虚拟页状态为未缓冲,虚拟页指向了磁盘地址。
操作系统和共享库的虚拟页被映射到了物理内存,因为操作系统和共享库已经在物理内存了,这些虚拟页的状态为已缓冲。
用户栈,运行时堆的虚拟页没有任何分配,不占用任何空间,这些虚拟页的状态为未分配。
那么进程虚拟地址空间的代码和数据,用户栈,运行时堆的物理内存什么时候分配呢,答案就是处理器用虚拟地址执行代码,读取数据时,这个下一章阐述。
虚拟地址访问物理内存先普及几个概念:
VPO即虚拟页偏移量:
虚拟地址由虚拟页号 虚拟页偏移量组成,虚拟页偏移量是相对某个虚拟页的偏移量。
PPO即物理页偏移量:
物理地址由物理页号 物理页偏移量组成,物理页偏移量是相对某个物理页的偏移量,
VPO等于PPO
页表(Page Table)PT:
页表是建立虚拟页号和物理页号映射关系的表结构,每个页表项(PTE)包括了有效位,物理页号,磁盘地址等信息,如下图:
页表与物理内存,虚拟内存的关系
由上图可以得知,操作系统可以根据页表项的有效位和地址信息判断出虚拟页目前所处的状态即未分配,已缓冲,未缓冲
如上图所示,页表有8个页表项,每个页表项里包含一个有效位和地址信息。
当页表项 PTE n的页表项有效位为0时,表示虚拟页 n没有缓冲在物理内存,可能在磁盘或者未分配,例如PTE 0页表项里存储的是null,表明虚拟页0即VP0是未分配状态,PTE 3里存储的是磁盘地址,表明虚拟页 3即VP3在磁盘里,但没有缓冲,VP3状态为未缓冲。
当页表项PTE n的页表项的有效位为1时,表示虚拟页n缓冲在物理内存,PTE n存储了物理页号,虚拟页 n的状态为已缓冲,例如PTE 1的页表项,有效位为1,则虚拟页VP1缓冲在了物理页中。
页表基址寄存器(PTBR):
每个进程都有自己的页表,CPU执行某个进程时,会先把该进程的一级页表起始地址存储到页表基址寄存器,这样CPU查找一级页表起始地址可以直接从寄存器查找,加快了查找效率。
好了,概念介绍到这里,先来看看虚拟地址翻译物理地址的过程,按照一级页表来演示,如下图所示: