前言

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


导读

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

符号名空间

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


逻辑地址

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

logical-address.png
图1
logical-address-1.jpg
图2
logical-address-2.jpg
图3

线性地址

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

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

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

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

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


物理地址

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


参考资料