接上节,分页机制是建立在分段机制之上,与其脱离不了干系,即使在分页机制下的进程也要先经过逻辑上的分段才行,每加载一个进程,操作系统按照进程中各段的起始范围,在进程自己的4GB虚拟地址空间中寻找可有空间分配内存段,此虚拟地址空间可以是页表,也可以是操作系统维护的某种数据结构,总之此阶段的分配是逻辑上的,并没有真正写入物理内存。代码段和数据段在逻辑上被拆分成以页为单位的小内存块。这时的虚拟地址虚如其名,不能存放任何数据。接着操作系统开始为这些虚拟内存页分配真实的物理内存页,它查找物理内存中可用的页,然后在页表中登记这些物理页地址,这样就完成了虚拟页到物理页的映射,每个进程都以为自己独享4G地址空间。

以上在宏观上笼统地介绍了分页机制下操作系统加载用户进程的整个流程,先让大家心中有数,了解我们下面所说的内容是什么。也许您对此过程并不十分理解,不过没关系,下面咱们开始从头说起。

映射这个概念大家应该比较清楚,对应的英文单词是map,意为地图。地图是对实际地理空间的一种抽象,地图上的每个位置都代表某个真实地理空间,这种地图上与地理上一一对应的关系就称为映射。

在内存地址中,最简单的映射方法是逐字节映射,即一个线性地址对应一个物理地址。比如线性地址为0x0,其对应的物理地址可以是0x0、0x10或其它你喜欢的数字,若线性地址为0x1,对应的物理地址为0x1、0x11或其它你喜欢的数字。我们需要找个地方来存储这种映射关系,这个地方就是页表,Page Table。页表就是个N行1列的表格,页表中的每一行(只有一个单元格)称为页表项PTE(Page Table Entry),其大小是4字节,页表项的作用是用来存储内存物理地址。当访问一个线性地址时,实际上就是在访问页表项中所记录的物理内存地址。

页表与物理内存关系示意如下图所示:

如果采用这种线性地址与物理地址一一映射的方案:

  1. 表中就应该有4G个页表项
  2. 32位的地址要用4字节的页表项来存储,页表总共大小是4Byte*4G =16GB。

分页机制本质上是将大小不同的大内存段拆分成大小相等的小内存块。以上方案其实就是将4GB空间划分成4G个内存块,每个内存块大小是1字节。页表也是存储在内存中的,为了表示32位地址,每个页表项必须要4字节,若按此方案,光是页表就要占 16GB内存,得不偿失,显然方案不合理。

以上方案不成立的原因是内存块数量太大了,也就是说,在总的4GB地址空间恒定不变的情况下,内存块尺寸选的太小了。为了找到合适的内存块大小,我们做下列分析与尝试。

任意进制的数字都可以分成高位部分和低位部分,若将低位部分理解为单位大小,高位部分则是这种单位的数量。如六万的十进制可表示为60000,也可以表示为60千。也就是将60000分成高位60和低位1000两部分。

为了节省页表空间,势必要将滑块往左调整,以使内存块尺寸变大,这样内存块数量变小,从而减少了页表项数量。如果滑块指向第20位,内存块大小则为2的20次方,即1MB,内存块数量则为2的12次方,即4K个。若滑块指向第12位,内存块大小则为2的12次方即4KB,内存块数量则为2的20次方,1M,即1048576个。这里所说的内存块,其官方名称是页,cpu中采用的页大小恰恰就是4KB,也就是上图中滑块的落点处。

一步步编写操作系统 37 一级页表与虚拟地址2相关推荐

  1. 一步步编写操作系统 38 一级页表与虚拟地址3

    接上,页是地址空间的计量单位,并不是专属物理地址或线性地址,只要是4KB的地址空间都可以称为一页,所以线性地址的一页也要对应物理地址的一页.一页大小为4KB,这样一来,4GB地址空间被划分成4GB/4 ...

  2. 一步步编写操作系统 36 一级页表与虚拟地址1

    为了给大家说清楚分页机制,我们先在宏观上说下cpu地址变换过程,先让大家有个直观的印象,如果有不明白的地方也不要着急,适时地不求甚解,有助于从全局上将知识融会贯通(这句话是我即兴说的,说得多好啊^^, ...

  3. 一步步编写操作系统 39 二级页表1

    前面讲述了页表的原理,并以一级页表做为原型讲述了地址转换过程.既然有了一级页表,为什么还要搞个二级页表呢?理由如下: 一级页表中最多可容纳1M(1048576)个页表项,每个页表项是4字节,如果页表项 ...

  4. 一步步编写操作系统 71 直接操作显卡,编写自己的打印函数71-74

    一直以来,我们在往屏幕上输出文本时,要么利用bios中断,要么利用系统调用,这些都是依赖别人的方法.咱们还用过一个稍微有点独立的方法,就是直接写显存,但这貌似又没什么含量.如今我们要写一个打印函数了, ...

  5. 一步步编写操作系统 69 汇编语言和c语言共同协作 70

    由于有了上一节的铺垫,本节的内容相对较少,这里给大家准备了两个小文件来实例演示汇编语言和c语言相互调用. 会两种不同语言的人,只是掌握了同一件事物的两种表达方式.人在学习一种新语言时,潜意识里是建立了 ...

  6. 一步步编写操作系统 62 函数调用约定

    由于我们要将c语言和汇编语言结合编程啦,所以一定会存在汇编代码和c代码相互调用的问题,有些事情还是要提前交待给大家的,本节就是要给大家说下函数调用规约中的那些事儿. 函数调用约定是什么? 调用约定,c ...

  7. 一步步编写操作系统 35 内存为何要分页

    一直以来我们都直接在内存分段机制下工作,目前未出问题看似良好,的确目前咱们的应用过于简单了,就一个loader在跑,能出什么问题呢.可是想像一下,当我们物理内存不足时会怎么办呢?比如系统里的应用程序过 ...

  8. 一步步编写操作系统 67 系统调用的实现1-2 68

    接上文: 系统调用的子功能要用eax寄存器来指定,所以咱们要看看有哪些系统调用啦,在linux系统中,系统调用是定义在/usr/include/asm/unistd.h文件中,该文件只是个统一的入口, ...

  9. 一步步编写操作系统 41 快表tlb 简介

    分页机制虽然很灵活,但您也看到了,为了实现虚拟地址到物理地址的映射,过程还是有些麻烦的.先要从CR3寄存器中获取页目录表物理地址,然后用虚拟地址的高10位乘以4的积做为在页目录表中的偏移量去寻址目录项 ...

最新文章

  1. SAP MM 采购附加费计入物料成本之二
  2. 干货丨一份机器学习的初学者指南
  3. 一个ant的简单实例
  4. css transform旋转属性
  5. HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)
  6. 基于Redis实现简单的分布式锁
  7. Spring Boot入门系列(十六)整合pagehelper,一秒实现分页功能!
  8. mysql pdo 插入没效果_MySQL分库分表后用PHP如何来完美操作
  9. Java基础学习总结(113)——异常最佳实践
  10. 随想录(内存屏障示例代码)
  11. 杭州趣链张帅:区块链应用落地,融合产业高速发展
  12. 关于接口测试的一些总结
  13. linux单块网卡绑定多个ip及网卡聚合绑定多个ip方法
  14. Android binder学习一:主要概念
  15. 关于java通过反射 获取/修改 对象属性值的一些注意事项
  16. java rpg对战_java实现模拟RPG格斗
  17. 【Matlab】在Simulink中仿真Park变换
  18. vux移动端UI组件库
  19. 用计算机绘制三维设计图步骤,3d效果图一般制作步骤
  20. 为什么学python?怎么学?怎样算学会?

热门文章

  1. 高可用-软件heartbeat的入门介绍
  2. jwPlayer为js预留的回调方法
  3. 【转载】MongoDB 1000W级数据 Insert和Query和Delete性能测试
  4. IBM T410 打开AHCI模式
  5. Know more about Cache Buffer Handle
  6. JAVA学习笔记——JAVA基础语法之精华
  7. [攻防世界][CTF][2020][MISC] 攻防世界 MISC writeup
  8. android 9格式吗,Android Studio中关于9-patch格式图片的编译错误
  9. 脚本启动慢_Linux 常用运维脚本,建议收藏
  10. 7-5 汉诺塔的非递归实现 (25 分)