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

Linux 2.x 内核对内存的管理

Linux 2.x 内核对内存的管理


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

每个进程都有一套页表,整个系统有一张GDT表(此机制由逻辑地址到线性地址变换,实际上是走了个形式,变换前后地址不变)

每个进程都有一套页表用于从线性地址到物理地址的映射变换。这样,每个进程都有一个4GB的逻辑空间。

(两进程的逻辑地址相同,但它们有不同的页表,故最终会映射到不同的物理位置)

实际上,此机制的地址翻译只有一步——直接把虚拟地址翻译成物理地址。                                                                                                                                                                                                                                                                                                                  

CPU通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到存储器之前先地址翻译成适当的物理地址。

地址翻译需要CPU硬件和操作系统之间的紧密合作。CPU芯片上叫做存储器管理单元(Memory Management Unit,MMU)的专用硬件,利用存放在主存中的页表来动态翻译虚拟地址,该表的内容是由操作系统管理的。



操作系统为每个进程提供了一个独立的页表,因而也就是一个独立的虚拟地址空间。


按需页面调度和独立的虚拟地址空间的结合,对系统中存储器的使用和管理造成了深远的影响。

简化链接独立的地址空间允许每个进程的存储器使用相同的基本格式,而不管代码和数据实际存放在物理存储器的何处

例如:一个给定的Linux系统上的每个进程都使用类似的存储器格式。文本节总还是从虚拟地址0x08048000处开始(32位),或者从0x400000处开始(64位)。数据和bss节紧跟在文本节后面。栈占据进程地址空间最高的部分,并向下生长。

这样的一致性极大地简化了链接器的设计和实现,允许链接器生成全链接的可执行文件,这些可执行文件时独立于物理存储器中代码和数据的最终位置的。

简化加载。虚拟存储器还使得容易向存储器中加载可执行文件和共享对象文件。

在ELF可执行文件中.text和.data节是连续的。要把这些节加载到一个新创建的进程中,Linux加载器分配虚拟页的一个连续的片,从虚拟地址0x08048000处开始(32位),或者从0x400000处开始(64位),把这些虚拟页标记为无效的(即未被缓存的),将页表条目指向目标文件中适当的位置


注意:加载器从不实际拷贝任何数据从磁盘到存储器。在每个页初次被引用时,要么是CPU取指令时引用的,要么是一条正在执行的指令引用一个存储器位置时引用的,虚拟存储器需要会按照需要自动调入数据页



 



Linux将虚拟存储器组织成一些段的集合。每个存在的虚拟页面都保存在某个区域中,而不属于某个区域的虚拟页是不存在的,并且不能被进程引用。内核不用记录那些不存在的虚拟页,而这样的页也不占用其他任何额外资源。

 

内核为系统中的每个进程维护一个单独的任务结构(源代码中的task_struct)。任务结构中的元素包含或者