(5). MMU(Memory Management Units)介绍
这一部分,和平台相关性非常大,因为每个CPU的MMU都有可能有自己的特性。这里我会以e6500平台为例子,介绍MMU的工作机制。
我们前面介绍了页面映射,其实就是在内存中建立了一个页表,当进程访问虚拟地址时,查询这个表,以获得实际的物理地址,那么这个表是由CPU(系统软件)来查询的吗?
如果CPU是工作在虚拟地址模式下,它实际上是没有办法直接访问到物理地址的。在这种情况下,也即意味着CPU不能够直接查询页表。这时候,必须要有MMU来执行这种页表查询操作。MMU也有自己的chahe,称之为TLB(Translation Look-aside Buffer),用来缓存PTE。
前面我说过,进程其实是一个抽象的空间,在这个空间中,程序编制者可以不用考虑实际的物理内存管理。每个进程有自己的虚拟地址空间,是进程私有的,CPU可以任意访问这个地址空间。而对于系统来说,我们需要考虑实际的物理地址空间,它是和具体设备相关(或者外部资源)的,内核需要在进程的虚拟地址和实际的物理地址之间建立一种映射关系。
我们可以这样说,用户进程需要解决的是特定的问题,而内核进程需要解决的是计算机内部的问题。什么是计算机内部的问题呢?这里我把像进程调度,内存管理,异常处理,外设管理这些问题归结为计算机自己需要解决的问题,或者是计算机自己的管理问题。
就像面向对象的编程一样,我们也可以把内核进程需要解决的问题,用面向对象的方式来理解。比如进程调度,那么内核可以把每个进程抽象成一个实体,这个实体具有自己的行为和记录这些行为的数据结构。对于内核进程调度模块来说,这些实体,就是其操作的对象。而 struct task_struct 就是这样一个抽象的类,它代表了一个进程在内核进程空间中的抽象。而 struct mm_struct 则描述了进程空间中的地址空间抽象。这里我再说下进程中的线程。其实上面的task_sturct结构体在linux中描述的是一个线程抽象。线程与进程的区别在于,进程是一个空间,线程是在这个空间中的事件。
为了理解这个概念,我们来看下现代几乎所有计算机都采用的架构(冯.诺依曼计算模型)。在这个架构中,CPU负责计算,通过从内存中获得指令和数据运行,在把计算结果保存到内存中,就是这么简单。那么我们理解的进程空间,就可以这样的。在这个空间中,有一个CPU和一个窗口(地址空间),CPU通过这个窗口获取指令和数据进行计算,再把结果通过这个窗口进行保存。至于这个窗口后面有什么,CPU是不关心的。如果CPU不去获得指令运行,那么这个进程空间我们说是不存在的,因为没有事件发生。就像我们这个宇宙,如果没有事件发生,那么我们的时间,空间也不存在一样。而在进程这个空间中发生的一系列事件组合,我们可以理解为就是一个线程。如果CPU执行了一些代码,发生的一系列事件,是有关联的&#x