嵌入式Linux之虚拟内存管理
概述
Linux系统中,每一个用户态进程独立地运行在自己的虚拟地址空间中。通常,对于32位系统,进程虚拟内存地址范围是0~232-1;对于64位系统,进程虚拟地址范围是0~264-1。
Linux虚拟内存遵循以下三个原则:
1)资源虚拟化,即用户态进程本身不用关心实际物理内存的占用情况、分配情况以及进程本身占用的物理内存地址范围;
2)进程隔离化,即用户态进程不能读取其他进程的虚拟地址空间;(共享内存?)
3)错误隔离化,用户态进程不能改写其他进程的虚拟地址空间,单个进程崩溃不会影响其他进程的运行,也不会导致系统崩溃;
Linux虚拟内存分配机制
1)虚拟内存地址和物理内存地址转换
Linux内存分配一般是以页(页大小通常为4KB)为单位,物理内存初始化时通过MMU进行页表划分,每个物理页均有一个唯一标识的页号。Linux用户态进程调用malloc()等函数申请内存时,会产生缺页中断,然后由Linux内核负责分配物理内存页给该进程。
Linux进程内存地址空间同样是按连续页进行划分的,因此在物理内存和虚拟内存之间,就存在一种映射关系。TLB(Translation Lookaside Buffer)就是负责加速转化物理内存和虚拟内存映射关系的硬件结构体。
Linux默认不使用超级页(每一个超级页由若干个子页组成,内存分配以子页为单位),因此,一般情况下,物理页和虚拟页大小相同。
有三种情况会产生Memory Hole(虚拟内存无法映射到这部分内存),即Reserved Memory、Memory-mapped I/O Devices以及未分配的内存(物理页表没有包含的内存)。
Linux内核负责通过操作MMU来建立和维护页表,MMU是用来进行虚拟内存地址和物理内存地址转换的单元。
2)按需分配
进程程序加载的时候,不会加载所有的代码段和数据段,但是会首先分配好虚拟内存页,当访问到虚拟内存页时,产生页错误,然后由内核处理,将代码段和数据段加载到物理页,并映射到虚拟页;同样,进程内存分配时,首先分配好虚拟内存页,只有当访问到虚拟内存页时,产生缺页中断,才会真正地分配物理内存页。
3)页分配和页交换
当物理内存分配完了,而进程还在申请新的内存页时,Linux内核会选择一个被占用的但是长期没有使用的(长时间没有读写)的物理内存页,将它的内存写入到swap space,然后将这个物理内存页映射到新的虚拟内存页,从而满足进程的需求。
页替换策略(replacement policy)决定哪一个物理页被替换,内容被写入交换分区。LRU策略(least recently used policy)是一个选项,但是它需要频繁地访问LRU list数据结构才能知道哪一个页最长时间没有被使用,从实用性的角度,Linux通常使用clock replacement或者not frequently used(NFU)策略。
缩略词:
VPN - Virtual Page Number
PFN - (Physical) Page Frame Number