日期:2014-05-16  浏览次数:20703 次

Linux内核中的内存(二)

版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127

 

内存除了管理本身的内存(物理内存)外,还必须管理用户空间中的进程的内存(虚拟内存),这个内存就叫进程地址空间。尽管一个进程可以寻址4GB的虚拟内存,但是这并不代表它就有权访问所有的虚拟内存,这些可以被访问的地址空间称为内存区域。如果一个进程访问了不在有效范围内的内存区域,或者以不正确的方式访问了有效地址,那么内核就会终止该进程,并返回段错误信息。

 

内核使用内存描述符结构体表示进程的地址空间,内存描述符由struct mm_struct结构体表示。分配内存描述符有两种方法:其一,fork函数利用copy_mm函数复制父进程的内存描述符,也就是current->mm域给其子进程,而子进程中的mm_struct结构体实际上是通过allocate_mm宏从mm_cachep_slab缓存中分配得到的。其二,当CLONE_VM被指定后,内核就不需要调用allocate_mm函数,而仅仅需要在调用copy_mm函数中将mm域指向其父进程的内存描述符。

 

内核线程与内存描述符

内核线程没有进程地址空间,也就没有自己的内存描述符,内核线程是没有用户上下文的。因为内核线程不需要访问用户空间内存,所以它们不需要有自己的内存描述符和页表。但是,当内核线程访问内核内存时,内核线程还是需要使用一些数据的,比如页表,为了避免内核线程为内核描述符呵呵页表浪费内存,内核线程直接使用前一个进程的内存描述符,而且仅仅使用前一个进程的内存描述符中和内核内存相关的信息,这些信息的含义和普通进程完全相同。

 

内存区域由struct vm_area_struct结构体描述,在linux内核中,内存区域又叫虚拟内存区域(VMAs),内核将每一个内存区域作为一个单独的内存对象管理,内存区域的位置就在[vm_start,vm_end]之间。在struct vm_area_struct中,我们有个flags域,这里面存放VMA标志,和物理页的访问权限不同,VMA标志反映了内核处理页面所需要遵守的行为准则,而不是硬件要求。另外提供了VMA操作来处理虚拟内存区域,包括open,close,fault,page_mkwrite,access函数。

 

内存区域的树型结构和内存区域的链表结构

红黑树的特点:第一,左边节点值小于右边节点值;第二,红节点的子节点为黑色;第三,树中的任何一条从节点到叶子的路径必须包括相同数量的黑色节点;第四,跟节点为红色;第五,红黑树搜索、插入、删除等操作的复杂度都是O(log(n))。链表用于需要遍历全部节点的时候,而红黑树适合在地址空间中定位特定内存区域的时候,内核为了内存区域上的各种不同的操作获得更高的性能,所以同时使用红黑树和链表这两种数据结构。

 

创建和撤销内存区域

如果创建内核区域,系统会调用do_mmap函数,在用户空间可以通过mmap函数获取内核函数do_mmap函数的功能。如果需要撤销内核区域,系统会调用do_munmap函数,在用户空间可以调用munmap函数获取内核do_munmap函数的功能。

原则上用户空间不能访问设备空间,mmap函数能把用户空间和设备空间进行映射,使得对用户空间的访问等同于对设备空间的访问。mmap具体功能有两个:其一,将普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能。其二,为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。

当用户调用mmap函数,内核会进行如下处理:第一,在进程的虚拟空间查找一块VMA;第二,将这块VMA进行映射;第三,如果设备驱动程序或者文件系统的file_operations定义了