您的位置:首页 > 运维架构 > Linux

Linux中物理页面的使用

2016-06-06 17:30 537 查看
在系统的初始化阶段,内核根据检测到的物理内存的大小,为每一个页面都建立一个page结构,形成一个page结构的数组,并使一个全局量mem_map指向这个数组。

又按需要将这些页面拼合成物理地址连续的许多内存页面“块”,再根据块的大小建立起若干“管理区”(zone),在每个管理区中则设置一个空闲块队列,以便物理内存也的分配使用。

交换设备的每个物理页面也要在内存中有个相应的数据结构,它只是一个计数,表示该页面是否已被分配使用,以及有几个用户在共享这个页面。

内核中定义了一个swap_info_struct数据结构,用以描述和管理用于页面交换的文件或设备。它的定义包含在include/linux/swap.h中。

当系统调用swap_on()指定一个文件用于页面交换时,就将该文件的swap_info_struct结构链入队列中。

只有映射到用户空间的页面才会被换出。

在内核中可以访问所有的物理页面。

按页面的内容和性质,用户空间的页面有下面几种:

1. 普通的用户空间页面;

2. 通过系统调用mmap()映射到用户空间的已打开文件的内容;

3. 进程间的共享内存区。

凡是映射到系统空间的页面都不会被换出。

按使用和周转的不同大致分成几类:

1. 内核代码和内核中全局量所占的内存页面既不需要分配也不会被释放,这部分空间是静态的。

2. 除此之外内核中使用的内存页面也要经过动态分配。

一类是一旦使用完毕便无保存的价值,所以立即便可释放回收。

内核中通过kmalloc()或vmalloc()分配、用作某些临时性使用和为管理目的而设的数据结构,如vma_area_struct数据结构。

内核中通过alloc_page()分配,用作某次临时性使用和为管理目的的内存页面,如每个进程的系统堆栈所在的两个页面,以及从系统空间复制参数时使用的页面等等。

另一类是虽然使用完毕了,但是其内容仍有保存的价值。把这些页面“养起来”,也许可以提高以后的操作效率。

这种用途的内核页面大致有:

在文件系统操作中用来缓冲存储一些文件目录结构dentry的空间;

在文件系统操作中用来缓冲存储一些inode结构的空间;

用于文件系统读/写操作的缓冲区。

可以将页面的换出和内存页面的释放分成两步来说,以防止“抖动”。

在准备换出一个页面时并不一定要把它的内容写入磁盘。

如果是“干净”的,不用写出去。即使是“脏”的页面,也不必立刻就写出去,而可以先从页面映射表断开,经过一段时间的“冷却”或“老化”后再写出去,从而变成“干净”页面。

物理内存页面换入/换出的周转要点:

1. 空闲。页面的page数据结构通过其队列头结构list链入某个页面管理区(zone)的空闲区队列free_area。页面的使用计数count为0.

2. 分配。通过函数__alloc_pages()或__get_free_page()从某个空闲队列中分配内存页面,并将所分配页面的使用计数count置为1,其page数据结构的队列头list结构则变成空闲。

3. 活跃状态。页面的page数据结构通过其队列头结构lru链入活跃页面队列active_list,并且至少有一个进程的(用户空间)页面表项指向该页面。每当为页面建立或恢复映射时,都使页面的使用计数count加1.

4. 不活跃状态(脏)。页面的page数据结构通过其队列头结构lru链入不活跃“脏”页面队列inactive_dirty_list,原则上不再有任何进程的页面表项指向该页面。每当断开页面的映射时都使页面的使用计数count减1.

5. 将不活跃“脏”页面的内容写入交换设备,并将页面的page数据结构从不活跃“脏”页面队列inactive_dirty_list转移到某个不活跃“干净”页面队列中。

6. 不活跃状态(干净)。页面的page数据结构通过其队列头结构lru链入某个不活跃“干净”页面队列,每个页面管理区都有一个不活跃“干净”页面队列inactive_clean_list。

7. 如果在转入不活跃状态以后的一段时间内页面受到访问,则又转入活跃状态并恢复映射。

8. 当有需要时,就从“干净”页面队列中回收页面,或退回到空闲队列中,或直接另行分配。

为了实现这种策略,在page数据结构中设置了所需的各种成分,并在内核中设置了全局性的active_list和inactive_dirty两个LRU队列,还在每个页面管理区中设置了一个inactive_clean_list。根据页面的page结构在这些LRU队列中的位置,就可以知道这个页面转入不活跃状态后时间的长短,为回收页面提供参考。

同时还通过一个全局的address_space数据结构swapper_space,把所有可交换内存页面管理起来,每个可交换内存页面的page数据结构都通过其队列头结构list链入其中的一个队列。

为加快在暂存队列中的搜索,又设置了一个page_hash_table。

通常来自同一个文件的页面就通过一个address_space数据结构来管理,而代表着一个文件的inode数据结构中有个成分i_data,那就是一个address_space数据结构。

用来管理可交换页面的address_space数据结构swapper_space只是个特例。

内核在为某个需要换入的页面分配了一个空闲内存页面以后,就通过add_to_swap_cache()将其page结构链入相应的队列。

现将给定的page结构通过add_page_to_inode_queue()加入到swapper_space中的clean_pages队列,其代码在mm/filemap.c中。

然后通过__add_page_to_hash_queue()将其链入某个杂凑队列中。

最后将页面的page数据结构通过lru_cache_add()链入到内核中的LRU队列active_list中,其代码在mm/swap.c中。

page数据结构可以通过同一个队列头结构lru链入不同的LRU队列,所以需要PG_active、PG_inactive_dirty以及PG_inactive_clean等标志位来表明目前是哪一个队列中。

用户进程在一定范围内对其本身的内存管理向内核提出一些要求,例如通过系统调用mmap()将一文件映射到它的用户空间。特别是特权用户进程,还掌握着对换入/换出机制的全局性控制权,就是系统调用swapon()和swapoff()。

这两个系统调用是为特权用户进程设置的。

Flash Memory不适合用作页面交换。

在Linux内核刚引导进来之初,所有的页面交换都是关闭的,内核在初始化期间要执行/etc/rc.d/rc.S命令文件,这个文件中的命令行之一就是系统调用swapop()相应的使用程序swapon。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: