首先解释一下什么是虚拟地址。Linux内核为每个进程提供了一个独立的虚拟地址空间,这个地址空间是连续的。虚拟地址空间内部分为两部分:内核空间和用户空间。不同字长(即单条CPU指令所能处理的最大数据长度)的处理器,其地址空间范围也不同。其中,所有进程的内核空间关联的是同一个物理内存。进程切换到内核态后,就可以访问内核空间内存了。我们下面描述的分割仅针对用户空间。有两种方法可以管理虚拟地址和物理地址之间的关系。1、段管理(Segment):通过段选择符和段内的偏移找到物理地址。用户空间从低地址到高地址分为五个不同的内存段。代码段(只读段),包括代码和常量等。数据段,包括全局变量等。堆,包括动态分配的内存,从低地址开始向上增长。文件映射段,包括动态库、共享内存等,都是从高地址向下增长的。(图中未显示)堆栈,包括局部变量和函数调用的上下文等。堆栈大小是固定的,通常为8MB。分段容易产生碎片,内存交换效率低(不易换出到磁盘)。为了解决这两个问题,内存分页出现了。2.分页:虚拟地址分为两部分,页号和页偏移量。MMU指定内存映射的最小单位,即页面,通常大小为4KB。为了解决页表项过多的问题,有两种方法:多级页表和大页。并非进程的所有虚拟内存都会分配物理内存,只有那些实际使用的虚拟内存才会分配物理内存。这被称为程序局部性原则。根据这个原理,为了提高访问速度,MMU(MemoryManageUnit)配备了一个硬件:TLB(TranslationLookasideBuffer)。用于缓存进程的公共页表。内存分段和内存分页并不是对立的,它们是结合使用的,通常称为段页内存管理。程序使用的地址称为逻辑地址;通过段内存管理映射出的地址称为虚拟地址(线性地址);通过页面内存管理将线性地址映射为物理地址。
