物理地址和逻辑地址

1. 物理地址和逻辑地址

物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。在前端总线上传输的内存地址都是物理内存地址,编号从0开始一直到可用物理内存的最高端。这些数字被北桥(Nortbridge chip)映射到实际的内存条上。物理地址是明确的、最终用在总线上的编号,不必转换,不必分页,也没有特权级检查(no translation, no paging, no privilege checks)。

逻辑地址:CPU所生成的地址。逻辑地址是内部和编程使用的、并不唯一。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址(偏移地址),不和绝对物理地址相干。

为什么会有这两种地址?

个人觉的原因在于逻辑地址分配更加灵活,可以允许不唯一,看起来也较为直观,例如,一段代码中分配数组,逻辑地址上是连续的,然而在物理地址上,这个数组所占用的页可能分散开来,物理地址上就是不连续的,这样对程序的可理解性上有影响。另外,有了逻辑地址这个概念,才能使用虚拟内存技术。

2. Paging,分页内存管理方案

(1) 分页的最大作用就在于:使得进程的物理地址空间可以是非连续的。

物理内存被划分为一小块一小块,每块被称为帧(Frame)。分配内存时,帧是分配时的最小单位,最少也要给一帧。在逻辑内存中,与帧对应的概念就是页(Page)。

逻辑地址的表示方式是:前部分是页码后部分是页偏移。

例如,已知逻辑空间地址为2^m个字节(也就是说逻辑地址的长度是m位),已知页大小是2^n字节。那么一共可以有2^(m-n)个页。因此页码部分会占m-n位,之后的n位,用来存储页偏移。

举个例子, 页大小为4B,而逻辑内存为32B(8页),逻辑地址0的页号为0,页号0对应帧5,因此逻辑地址映射为物理地址5*4+0=20。逻辑地址3映射物理地址5*4+3=23。逻辑地址13(4*3+1,页号为3,偏移为1,因此帧号为2),映射到物理地址9。

物理地址和逻辑地址

采用分页技术不会产生外部碎片(内存都被划分为帧),但可能产生内部碎片(帧已经是最小单元,因此帧内部可能有空间没有用到)。

按概率计算下来,每个进程平均可有半个帧大小的内部碎片。

(2) 页表的硬件实现

上一小节中写到页表是逻辑地址转化到物理地址的关键所在。那么页表如何存储?

每个操作系统都有自己的方法来保存页表。绝大多数都会为每个进程分配一个页表。现在由于页表都比较大,所以放在内存中(以往是放在一组专用寄存器里),其指针存在进程控制块(PCB)里,当进程被调度程序选中投入运行时,系统将其页表指针从进程控制块中取出并送入用户寄存器中。随后可以根据此首地址访问页表。

页表的存储方式是TBL(Translation look-aside buffer, 翻译后备缓冲器)+内存。TBL实际上是一组硬件缓冲所关联的快速内存。若没有TBL,操作系统需要两次内存访问来完成逻辑地址到物理地址的转换,访问页表算一次,在页表中查找算一次。TBL中存储页表中的一小部分条目,条目以键值对方式存储。

物理地址和逻辑地址

(3) 页表的数据结构

a.

今年是2013年,现有的笔记本电脑,内存地址空间一般为2^32字节以上。对于具有32位逻辑地址空间的计算机系统,如果系统的页大小为4KB(2^12B),那么页表可以拥有2^(32-12)个,也就是一百多万个条目,假设每个条目占有4B,那每个进程都需要4MB的物理地址空间来存放页表本身。而且,页表本身需要分配在连续内存中。

为此,Hierarchical Paging(层次化分页)被提出,实际上就是将页号分为两部分,第一部分作为索引,第二部分作为页号的偏移。

以一个4kb页大小的32位系统为例。一个逻辑地址被分为20位的页码和12位的页偏移。因为要对页表进行再分页,所以该页号可分为10位的页码和10位的页偏移。这样一个逻辑地址就表示如下形式:

物理地址和逻辑地址

 

地址转换过程如下:

 

物理地址和逻辑地址

地址由外向内转换,因此此方法也被称为forward-mapped page table(向前映射表)