1 分页机制
早期计算机直接使用物理地址进行内存的使用和管理,但是硬件资源有限,而且不同的程序需要使用不同的物理地址,这样给程序的管理和运行造成了很大的难度,而且极易造成一个程序覆盖其他程序的问题,使正常运行的程序出现错误。
针对以上问题提出了使用虚拟地址与物理地址映射的管理方式,这样每个程序都可以使用相同的地址,但是由于每个进程使用不同的叶表,所以使用不同的物理页,这样就可以解决以上的问题。
下图为Linux下分页机制的实现原理,虚拟地址经过页面目录和页表的查询,找到页物理地址,最后将偏移量合成为物理地址。
2 分段机制
其实分页机制已经能够满足虚拟内存管理和保护模式的要求,现在的一些构架的处理器完全不使用分段机制。段机制是x86遗留的历史问题。
下图为分段机制原理图,其实现核心是一个全局的描述符表GDT,这个表作用很大,比如每个进程都有一个TSS段,但是当前进程如果切换到另一个进程,一定要使用到另一个进程的TSS段,由于使用不同的叶表,肯定无法相互访问各自的地址空间,这个时候全局描述符表解决了这一问题,他就像是一个共享的地址空间,这样就能很好的相互访问了。
3 两个机制的结合
有了新方法,但是也不能摒弃旧的,需要新旧结合,所以需要将两个机制相互结合。
下图为完整的地址转换过程图:
4 地址空间分配
虚拟地址空间由地址总线位数决定,现在的计算机大多是32位的。
32位也就是4G大小,linux中将0-3G的线性地址由用户态程序使用,3G-4G的线性地址留给内核态使用。
虽然内核态只是用1G空间,但是它管理着整个物理地址空间,Linux内核将物理地址分成3个区,ZONE_DMA(0-16M),ZONE-NORMAL(16-896M),ZONE_HIGHTMEM(896M - ~)。
ZONE_DMA区用于DMA设备的映射,DMA设备可以不通过CPU将数据发送的内存,这样CPU可以处理其他事务,从而提高系统的效率。
ZONE_NORMAL区为内核使用的区域,这个区主要被内核所使用,当然在用户态出现缺页时,也会在此区中分配物理页。
ZONE_HIGHTMEN区,其实是一个让我开始很困惑的去,书上说他是高端内存,内核使用不到它,那岂不是1G以上的内存条也没用,因为内核都够不到,怎么将它分配给进程使用,后来才明白什么意思。内核使用不到ZONE_HIGHTMEN区意思是其物理地址不能被内核所使用,但是能够被内核所操控,控制它映射给用户态程序。用户态程序在缺页时首先在ZONE_HTIGHTMEN区寻找页,如果找不到就需要到ZONE_NORMAL去寻找了,而内核在缺页时只能在ZONE_NORMAL里寻找。