物理页面的分配使用函数:
static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
参数gfp_mask表示分配的策略,order表示所需物理块的大小。gfp_mask作为下标查找数组node_zonelists[]决定具体的分配策略。
其具体分配的流程如下:
1. 如果只分配单个页面且等待分配完成,又不是用于管理目的,把direct_reclaim设为1,就从不活跃的干净页面缓冲队列中回收一块,因为这些页面很难保证连续。
2.如果当前页面总量比较充裕,内存分配压力较小,就用rmqueue()试图从管理区分配。每个管理区都有 zone->free_area指向管理区的空闲区。如果页面总量已经将到最低点,唤醒内核线程kreclaimd辅助回收一些页面。
3.rmqueue()从管理区挨个扫描直到分配成功或最终失败,如果失败就加大力度。其一降低管理区保存水位的要求,其二是把缓冲在管理区不活跃的干净页面也考虑进去。成功就返回一个page结构指针,指向页面块的第一个页面。
4.如果还不行的话,就唤醒内核线程kswapd设法换出一些页面。如果分配策略对内存分配志在必得,则让系统再进行一次调度,并且让当前进程为其他进程让路。如果还是失败,就要检查当前正在分配内存的进程是什么。如果是kswapd或kreclaimed,他们的task_struct里的flags字段的PF_MEMALLOC标志为1,会比一般的进程更重要。
5.此时可以调用page_launder()洗干净脏页面,并把它们回收整合成大的页面块。如果还是失败,就表示管理区的页面总量真的很少。就要再次加大力度,此时判断的标准是高于 z->pages_min。如果还是失败就表明系统出现问题了。