日期:2014-05-16  浏览次数:20804 次

Linux 0.12 内核对内存的管理

Linux 0.12 内核对内存的管理


着重点在于分段,用分段的机制把进程间的虚拟地址分隔开。

每个进程都有一张段表LDT,整个系统有一张GDT表,且整个系统只有一个总页表。


 

地址翻译过程为:

程序中给出的32位地址(实际上被看做段内偏移地址),再根据代码段寄存器CS中的16位段选择子,可在GDT或LDT中查找相应的段描述符。从段描述符中提取段的基地址,与程序给出的32位地址相加,得到结果为线性地址

根据此线性地址查找系统页目录表,再查二级或是多级页表,最终得到物理地址。

 

此方式系统只有一个4G的线性地址空间由各进程共享(各个进程共享一套页表)。(32位系统一个虚拟段的最大长度,理论上为4G)

Linux 0.12内核人工定义的最大任务数为64个,每个任务的逻辑地址范围是64MB,故全部任务所使用的线性地址空间范围是64MB*64=4GB。

(即限定一张LDT表所有项的管辖范围是64MB。理论上其一项的管辖范围就是4GB)

 

内存寻址


(8086为了能寻址1M的空间,设计了称为段(Segment)的寻址技术。由于后来CPU的发展,这种寻址技术实际上是不必要的,但为了保持兼容,80x86也用了段寻址技术。)

 

段地址部分使用16位的段选择子指定,其中14位可以选择,即16384个段。

(在保护模式下,段寄存器中的值为段表中的段选择子。在实模式下,段寄存器中的值为段表基址)

段内偏移地址使用32位的值来指定,因此段内地址可以是0~4GB。即一个段的最大长度可达4G。

程序中由16位的段和32位的偏移构成的48位地址或长指针称为一个逻辑地址(虚拟地址)

 

80x86为段部分提供了6个存放段选择子的段寄存器:CS、DS、ES、SS、FS和GS。

其中,CS总是用于寻址代码段,而堆栈段则专门使用SS段寄存器。

CS寻址的段称为当前代码段。此时EIP寄存器中包含了当前代码段内下一条要执行指令的段内偏移地址。因此要执行指令的地址可表示成CS:[EIP]。

SS寻址的段称为当前堆栈段。栈顶由ESP寄存器内容指定。因此堆栈顶处地址是SS:[ESP]。

另外4个段寄存器是通用段寄存器。当指令中没有指定所操作数据的段时,那么DS将是默认的数据段寄存器。

 


地址变换


CPU的内存管理给程序员提供了这样一个抽象的内存模型:


即程序员(无论是汇编的还是高级语言的)可以把内存分布看做是如上图所示,可以认为内存中只有自己的程序,自己独占CPU。

这是硬件和操作系统一起提供给程序员的简单抽象。

(底层的实现:地址变换、任务切换等对程序员是透明的)

 

程序(无论是汇编的还是高级语言的)中的地址是由两部分构成的逻辑地址。这种逻辑地址并不能直接用于访问物理内存,而需要使用地址变换机制将它变换或映射到物理内存地址上。内存管理机制即用于将这种逻辑地址转换成物理内存地址。

 

80x86在从逻辑地址到物理地址变换过程中使用了分段和分页两种机制。

第一阶段使用分段机制,把程序的逻辑地址变换成处理器可寻址的内存空间(称为线性地址空间)

第二阶段使用分页机制,把线性地址转换为物理地址

第一阶段的分段变换总是使用的,而第二阶段的分页机制则是供选用的。若没有启用分页机制,那么分段机制产生的线性地址空间就直接映射到处理器的物理地址空间上。




物理地址空间定义为处理器在其地址总线上能够产生的地址范围。(主板提供的统一编址)