Linux内核内存管理( 四 )


图-Linux缺页中断处理
一旦异常处理程序确定异常是有效内存区域中的有效缺页中断,将调用体系结构无关的函数() 。如果请求页表项不存在,就分配请求的页表项,并调用() 。
第一步调用检查PTE标志位,确定其是否在内存中,然后调用()检查PTE是否分配 。如果PTE还没有分配的话,将调用()处理请求页面的分配,否则说明该页已经交换到磁盘,也是调用()处理请求换页 。如果换出的页面属于虚拟文件则由()处理 。
第二步确定是否写页面 。如果PTE写保护,就调用(),因为这个页面是写时复制页面 。COW页面识别方法:页面所在VMA标志位可写,但相应的PTE确不是可写的 。如果不是COW页面,通常将之标志为脏,因为它已经被写过了 。
第三步确定页面是否已经读取及是否在内存中,但还会发生异常 。这是因为在某些体系结构中没有3级页表,在这种情况下建立PTE并标志为新即可 。
2、请求页面分配:
第一次访问页面,首先分配页面,一般由()填充数据 。如果父VMA的->提供了()函数,则用它填充数据;否则调用()匿名函数来填充数据 。如果被文件或设备映射,如果时文件映射,()将替代()函数,如果由虚拟文件映射而来,则() 。每种设备驱动将提供不同的()函数,该函数返回 page结构 。
3、请求换页:
将页面交换至后援存储器后,函数()负责将页面读入内存,将在后面讲述 。通过PTE的信息就足够查找到交换的页面 。页面交换出去时,一般先放到交换高速缓存中 。
缺页中断时如果页面在高速缓存中,则只要简单增加页面计数,然后把它放到进程页表中并计数次缺页中断发生的次数 。如果页面仅存在磁盘中,Linux将调用()读取它及后续的若干页面 。
4、页面帧回收:
除了slab分配器,系统中所有正在使用的页面都存放在页面高速缓存中,并由page->lru链接在一起 。Slab页面不存放到高速缓存中因为基于被slab使用的对象对页面计数很困难 。除了查找每个进程页表外没有其他方法能把 page映射为PTE,查找页表代价很大 。如果页面高速缓存中存在大量的进程映射页面,系统将会遍历进程页表,通过()函数交换出页面直到有足够的页面空闲,而共享页会给()带来问题 。如果一个页面是共享的,同时一个交换项已经被分配,PTE就会填写所需信息以便在交换分区里重新找到该页并将引用计数减1 。只有引用计数为0时该页才能被替换出去 。
内存和磁盘缓存申请越来越多的页面但确无法判断如何释放进程页面,请求分页机制在进程页面缺失时申请新页面,但它却不能强制释放进程不再使用的页面 。The Page Frame(PFRA)页面回收算法用于从用户进程和内核cache中回收页面放到伙伴系统的空闲块列表中 。PFRA必须在系统空闲内存达到某个最低限度时进行页面回收,回收的对象必须是非空闲页面 。
可将系统页面划分为四种:
1)不可回收的,包括空闲页面、保留页面设置了标志、内核动态分配的页面、进程内核栈的页面、设置了标志的临时锁住的页面、设置了标志的内存页面 。
2)可交换的页面,用户进程空间的匿名页面(用户堆栈)、tmpfs文件系统的映射页面(入IPC共享内存页面),页面存放到交换空间 。
3)可同步的页面,入用户态地址空间的映射页面、保护磁盘数据的页面缓存的页面、块设备缓冲页、磁盘缓存的页面(入inode cache),如果有必要的话,需同步磁盘映像上的数据 。
4)可丢弃的页面,入内存缓存中的无用页面(slab分配器中的页面)、 cache的页面 。
PFRA算法是基于经验而非理论的算法,它的设计原则如下: