逻辑地址、线性地址、物理地址

前言

本文只是站在最方便理解的角度,来阐述一下逻辑地址、线性地址、物理地址。更多细节可以阅读参考资料


导读

  1. 符号名空间
  2. 逻辑地址
  3. 线性地址
  4. 物理地址
  5. 参考资料

符号名空间

编写程序的时候,使用的地址空间叫符号名空间,在符号名空间中,通过符号(也就是变量名)来引用一块内存。


逻辑地址

编译后的程序,所使用的地址空间就是逻辑地址空间逻辑地址是相对于段的基地址的偏移。

  • CPU将整个地址空间划分成若干个分段,比如内核代码段、内核数据段、用户代码段、用户数据段等等。每个段都有权限位,让不同的程序可以访问不同的段。
    1.png
图1
  • 段描述符是用来描述每个段的。段描述符由8个字节组成,其中最重要的就是段的基地址。多个段描述符组成了段描述符表,段描述符表分为GDT(全局段描述符表,每个CPU有一个)和LDT(局部段描述符表,每个进程有一个)。
  • 每个逻辑地址是由两部分组成的,[段选择符:偏移],段选择符的组成如图2所示,其中:
    • TI标识了使用LDT还是GDT
    • 索引号就是段描述符表中的索引
    • 整体的转换流程如图3所示:
      1. 根据段选择符中的TI位确定使用GDT还是LDT,再根据寄存器获取要使用的段描述符表的地址
      2. 段选择符的前13位是段描述符表中的索引,据此得到段描述符,这样就取到了段的基地址Base
      3. Base + offset就是要转换的线性地址了
        1.jpg
图2

1.jpg

图3

线性地址

线性地址是逻辑地址转换成物理地址的中间层,CPU的MMU(内存管理单元)负责将线性地址转换成物理地址。
为了提升效率,CPU进行内存管理的基本单位并不是字节,而是,每个页4KB。因此在32位机上,线性地址会被划分为 2^32 / 4K = 2^20 = 1MB个页。
同样的,CPU也会将物理地址空间划分成页,称每个页为物理页
理论上,每个页都应该对应一个物理页。而一个地址是32位,4个字节。那么存储这个对应关系就需要4MB的内存。
为了节省空间,引入了页目录页表的概念,每个进程都有自己的页目录,它的地址存储在CPU的寄存器中。
以32位机为例。一个32位的线性地址被分为3部分:

  • 页目录索引(10位)
  • 页表索引(10位)
  • 偏移(12位)

整个转换过程如图4所示:

  1. 从CPU寄存器cr3中获取到页目录地址(操作系统在调度进程的时候,负责将页目录地址放入寄存器)
  2. 根据线性地址的页目录索引部分,去页目录中找到页表
  3. 根据线性地址的页表索引部分,找到页的起始地址
  4. 起始地址 + 偏移,就得到了物理地址
    1.jpg
图4

下面要特别强调的是:
物理内存通常是小于线性地址空间的,并且有许多进程在同时运行,因此不可能提前给进程建立页表

Linux利用CPU的一个机制解决了这个问题。进程创建后我们可以给页目录的表项值都填0,CPU在查找页表时,如果表项的内容为0,则会引发一个缺页异常,进程暂停执行,Linux内核这时候可以通过一系列复杂的算法给分配一个物理页,并把物理页的地址填入表项中,进程再恢复执行。


物理地址

可以形而上地,将物理地址理解为:将物理内存的存储单元从0开始编号,每个编号就是对应存储单元的物理地址。
综上,整个转换过程就是:符号名 -> 逻辑地址 -> 线性地址 -> 物理地址。


参考资料

感谢浏览tim chow的作品!

如果您喜欢,可以分享到: 更多

如果您有任何疑问或想要与tim chow进行交流

可点此给tim chow发信

如有问题,也可在下面留言: