Linux内存管理(四)——物理内存管理

来源:互联网 发布:淘宝模块怎么添加名称 编辑:程序博客网 时间:2024/05/16 12:34

内存组织

基本单位4KB页面-Page结构,总的Page数组mem_map[]数组;
均匀介质中:
Node(总的仓库,page数组)->
ZONE_DMA、ZONE_NORMAL、ZONE_HIGHMEM(用于物理内存>1GB空间)->
zone_struct结构->
多组队列,free_area_struct,inactive_clean_pages,inactive_dirty_pages,active->
2^0~2^10页面组成的块的队列
非均匀介质NUMA:
pglist_data(小仓库,page数组)链->
ZONE_DMA、ZONE_NORMAL、ZONE_HIGHMEM(用于物理内存>1GB空间)->
zone_struct结构->
多组队列,free_area,inactive_clean_list,inactive_dirty_list,active_list->
2^0~2^10页面组成的块的队列
注意:
这些队列均是LRU队列,最近最少使用
LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面!
LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页!

内存分配与释放

总体流程

1、空闲。
页面page数据结构通过其队列头链入对应管理区空闲队列free_area。页面计数count=0
2、分配
通过函数_alloc_pages()或_get_free_page()从空闲队列分配内存页面,并将所分配页面计数为1,其从free_area队列移除
如果无进行内存交换操作
3、上个页面链入活跃队列active_list,并且至少有一个进程的用户空间指向该页面。每当为其页面再建立或恢复映射时,页面计数count+1;
4、每当断开页面映射,页面计数-1。如果修改了页面内容且页面不再用即count=0,则链入inactive_dirty_list队列。
5、将不活跃脏页面写入交换设备,从inactive_dirty_list移到inactive_clean_list队列。
6、如果之后又收到访问,则又到活跃页面并恢复映射。
7、需要时则从“干净队列”中回收页面。

buddy算法

伙伴算法——分配多个页面:
标记每个页面是否使用,位图0/1。
则0的伙伴是1;0、1的伙伴是1、2;0、1、2、3伙伴是4、5、6、7;类似。
为0表示两个块都空闲,否则为1。
如何分配:
假如系统需要4(2*2)个页面大小的内存块,该算法就到free_area[2]中查找,如果链表中有空闲块,就直接从中摘下并分配出去。如果没有,算法将顺着数组向上查找free_area[3],如果free_area[3]中有空闲块,则将其从链表中摘下,分成等大小的两部分,前四个页面作为一个块插入free_area[2],后4个页面分配出去,free_area[3]中也没有,就再向上查找,如果free_area[4]中有,就将这16(2*2*2*2)个页面等分成两份,前一半挂如free_area[3]的链表头部,后一半的8个页等分成两等分,前一半挂free_area[2]
的链表中,后一半分配出去。假如free_area[4]也没有,则重复上面的过程,知道到达free_area数组的最后,如果还没有则放弃分配。
如何释放:
当释放一个块时,先在其对应的链表中考查是否有伙伴存在,如果没有伙伴块,就直接把要释放的块挂入链表头;如果有,则从链表中摘下伙伴,合并成一个大块,然后继续考察合并后的块在更大一级链表中是否有伙伴存在,直到不能合并或者已经合并到了最大的块

内存与磁盘交换

页面交换:

定期换出:

守护线程kswapd至少每秒一次循环:
1、发现物理页短缺情况下,预先找出页面,断开页面映射,为页面换出做准备;
当然不一定要断开活跃页面映射,即先看不活跃-干净队列,再看不活跃-脏队列,最后再断开映射。
2、将脏页面写入交换设备
page_launder()写入交换设备
3、其他还对slab分配对象进行回收

原创粉丝点击