文档章节

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

我叫半桶水
 我叫半桶水
发布于 07/15 22:49
字数 2076
阅读 11
收藏 0

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(的地址)。

© 著作权归作者所有

共有 人打赏支持
我叫半桶水
粉丝 0
博文 26
码字总数 71642
作品 0
西安
私信 提问
操作系统常用的调度算法总结

1 常见的批处理作业调度算法   1.1 先来先服务调度算法(FCFS):   就是按照各个作业进入系统的自然次序来调度作业。这种调度算法的优点是实现简单,公平。其缺点是没有考虑到系统中各种...

fx677588
2017/09/09
0
0
安卓如何回收返回栈底部页面中的图片内存?

安卓应用为了能打开几十个有图片的页面,比如60个,使用默认的内存管理机制是不够的。经测试使用默认的内存管理机制打开10个左右的含图片的页面时app占用内存就达到了200多兆,这导致新开的页...

logan676
2017/07/12
54
0
首位国人惠新宸加入PHP官方开发组

PHP开发组终于有了国人参与,最近Laruence(真名惠新宸),加入了PHP语言官方开发组。做PHP的同学一定很熟悉他了,他的博客风雪之隅发表了很多PHP源代码分析和扩展开发相关的文章。 他使用P...

刘秀
2011/11/04
1K
8
用于开发 Web 应用的 PHP 框架--Yaf

Yaf 是一个 C 语言编写的 PHP 框架,Yaf 的特点: 用 C 语言开发的 PHP 框架,相比原生的 PHP,几乎不会带来额外的性能开销。 所有的框架类,不需要编译,在 PHP 启动的时候加载,并常驻内存...

Laruence
2011/10/17
46.5K
10
Linux 性能监测:Memory

这里的讲到的 “内存” 包括物理内存和虚拟内存,虚拟内存(Virtual Memory)把计算机的内存空间扩展到硬盘,物理内存(RAM)和硬盘的一部分空间(SWAP)组合在一起作为虚拟内存为计算机提供...

david_bj
2014/12/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

开源软件会被云杀死吗 ?

本文转载云头条,原作者:Michael Stiefel是Reliable Software公司的负责人,是一名软件架构和开发顾问。 文章要点 虽然开源开发不会消失,但商业开源厂商的未来不是很有希望。随着全面管理的...

linuxCool
22分钟前
0
0
OSChina 周三乱弹 —— 谈什么对象?睡什么觉?

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @胖达panda :最肯忘却古人诗,最不屑一顾是相思。分享童丽的单曲《红豆生南国》: 《红豆生南国》- 童丽 手机党少年们想听歌,请使劲儿戳(这...

小小编辑
26分钟前
43
3
stylus

stylus基础教程,stylus实例教程,stylus语法总结

miaojiangmin
今天
3
0
PHP生成CSV之内部换行

当我们使用PHP将采集到的文件内容保存到csv文件时,往往需要将采集内容进行二次过滤处理才能得到需要的内容。比如网页中的换行符,空格符等等。 对于空格等处理起来都比较简单,这里我们单独...

豆花饭烧土豆
今天
2
0
使用 mjml 生成 thymeleaf 邮件框架模板

发邮件算是系统开发的一个基本需求了,不过搞邮件模板实在是件恶心事,估计搞过的同仁都有体会。 得支持多种客户端 支持响应式 疼彻心扉的 outlook 多数客户端只支持 inline 形式的 css 布局...

郁也风
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部