内存管理之10:内存页面的周转

date: 2014-10-03 19:09

1 页面交换策略

所谓内存页面的周转有两方面的含义:其一是物理页面的分配、使用和回收,并不一定涉及页面的盘区交换;其二才是盘区交换,盘区交换的最终目的也是为了页面回收。并非所有的内存页面都可以交换出去,只有映射到用户空间的内存页面才会被换成,而内核即系统空间的页面不在此列。需要指出,内核可以访问所有的内存页面,换言之,所有物理页面(HIGH_MEM区的高端物理内存除外)在系统空间中都有映射的,所谓“用户空间的页面”,是指在至少一个进程的用户空间中有映射的页面,反之就是内核使用的页面。

显然最简单的页面交换策略就是,每次缺页异常时就分配一个内存页面,并从磁盘页面上读入内容;如果没有空闲的内存页面可用分配,就设法将一个或多个内存页面换出到磁盘此面上,从而腾出一些页面来。但这种消极应对的策略有一个缺陷,这种临时抱佛脚总发生在系统忙碌的时候(系统忙着分配页面哩)而没有调度的余地。比较积极的办法是定期地,最好是在系统空闲时,挑选一些内存页面换出而腾出依稀内存空间,保持一定的空闲内存供应量,使得在缺页异常发生时,有页面可分配。至于挑选的准则,一般都是LRU即“最近最少使用”准则。但这种策略实施起来比较困难,因为实际上并不存在一种准确预测页面访问的方法,可能上一秒刚刚把一个内存页面换出,下一秒,系统又要访问这个物理页面,只好又把它赶快换进来,造成所谓的页面“抖动”。

为了防止这种情况发生,页面的换出与释放分两步走。当系统挑选出若干页面准备换出时,将这些页面的内容写入磁盘页面,相应的页面表项pte_t也变身为swp_entry_t(P表中为0,表示页面不再内存中),但所占据的内存页面并不立即释放(内存页面上的内容仍保留),而是将其page结构留在一个缓冲队列中,使其从“活跃状态”变为“不活跃状态”。就像NBA球员从“首发”变为“替补”,至于是否要让他去看“饮水机”即内存页面的最终释放,则要继续考察一段时间再说。这样如果一个页面被换出后又被立即访问从而触发页面异常,就可以从缓冲队列(替补席)里找到对应的内存页面,再次为之建立映射(swp_entry_t变成pte_t),从“不活跃状态”变为“活跃状态”。由于此页面尚未被释放,其上的内容仍是有效的,就不需要从磁盘页面上读入内容了。反之,如果经过一段时间的老化,一个不活跃的页面还是没有受到访问,此时已经不再有(用户空间中的)虚存页面映射到该内存页面上了,该内存页面到了最后释放的时候了。

这种策略显然可以减少抖动,但还是有改进的余地。首先,在页面换出时,如果自从上次页面换出内存页面中的内容并没有改变,那么这个页面就是“干净”的,也就是与磁盘页面上的内容一致。这样的页面当然不用费事再写到磁盘页面上。其次,即使是“脏”页面,也不必立即写出去,而可以先从页面映射表断开,经过一段时间的“冷却”或“老化”后再写出去,从而变成“干净”的页面。而至于“干净”的页面,也不用着急立即释放,可以继续缓冲直到真有必要时再释放,因为回收一个干净的页面,代价是很小的。

2 一个内存页面的旅行

物理页面周转要点如下图所示:

物理内存页面的旅行

  • ①空闲。page结构通过list链入到内存管理区的空闲队列free_area中,其使用计数count为0;
  • ②分配。page结构从空闲队列中脱链链,其链表头list空闲,使用计数count为1;
  • ③活跃状态。page结构通过链表头lru链入全局的活跃页面队列active_list,并通过链表头list链入swapper_space中干净页面队列clean_pages;
  • ④不活跃脏状态。page结构通过链表头lru链入全局的不活跃脏页面列表inactive_dirty_list,并通过链表头list链入swapper_space中脏页面列表dirty_pages。原则上不再有任何进程的页面表项指向该页面,每次断开页面映射时都使page结构的引用计数减1;
  • ⑤不活跃干净状态。将不活跃脏页面的内容写入磁盘页面,内存页面就被“洗白”了,进入不活跃干净状态。page结构通过链表头lru链入管理区的不活跃干净页面队列inactive_clean_list;
  • ⑥如果在转入不活跃状态一段时间内页面受到访问,则又转入活跃状态(状态③)并恢复映射;
  • ⑦当有需要时,就从不活跃干净的页面队列中回收页面,或者退回到空闲队列中(图中的状态⑦),或者直接分配出去(图中状态②)

图中涉及到结构及变量说明如下:

  • active_list和inactive_dirty_list是两个全局性的LRU队列。此外内核还在每个内存管理区设置了一个inactive_clean_list。page通过链表头lru链入这三个LRU队列之一,根据page在LRU队列中的位置,就可以知道page的“冷却”或“老化”程度,为页面回收提供依据。为什么active_list和inactive_dirty_list是全局队列而inactive_clean_list却率属于某个内存管理区?原因是系统在挑选要换出的内存页面时“一视同仁”,不区分内存页面所在的管理区。而当页面进入不活跃干净状态时,该页面有可能被回收到其所在管理区的空闲队列中,或者是再被分配出去,这两种情况都和内存管理区相关,所以莫不如将不活跃干净页面归到各自的内存管理区名下。
  • 因为页面page可以在三个LRU队列之间转移,所以需要page结构中设置标志(flag字段),来表示当前在哪个LRU队列中,这三个标志分别是:PG_active、PG_inactive_dirty和PG_inactive_clean。
  • 此外,内核还通过一个全局address_space结构swapper_space来管理所有可交换的内存页面,每个可交换的内存页面都通过page结构中链表头list链入其中的一个队列。address_space结构以及全局变量swapper_space的定义如下:
        <include/linux/fs.h>
        
        struct address_space {
        	struct list_head	clean_pages;	/* list of clean pages */
        	struct list_head	dirty_pages;	/* list of dirty pages */
        	struct list_head	locked_pages;	/* list of locked pages */
        	unsigned long		nrpages;	/* number of total pages */
        	struct address_space_operations *a_ops;	/* methods */
        	struct inode		*host;		/* owner: inode, block_device */
        	struct vm_area_struct	*i_mmap;	/* list of private mappings */
        	struct vm_area_struct	*i_mmap_shared; /* list of shared mappings */
        	spinlock_t		i_shared_lock;  /* and spinlock protecting it */
        };
        
        
        
        <mm/swap_state.c>
        
        static struct address_space_operations swap_aops = {
        	writepage: swap_writepage,
        	sync_page: block_sync_page,
        };
        
        //swapper_space的定义如下:
        struct address_space swapper_space = {
        	LIST_HEAD_INIT(swapper_space.clean_pages),
        	LIST_HEAD_INIT(swapper_space.dirty_pages),
        	LIST_HEAD_INIT(swapper_space.locked_pages),
        	0,				/* nrpages	*/
        	&swap_aops,
        };

  swapper_space.a_ops被初始化成swap_aops,swap_aops定义的换出到磁盘页面的函数为swap_writepage。

  还记得page结构中有一个address_space结构成员mapping吗?当把一个page加入到swapper_space中的某个队列时,page. mapping就被赋值成swapper_space(的地址)。

转载于:https://my.oschina.net/u/3857782/blog/1854534

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值