Linux进程地址空间
Linux进程地址空间
2011年04月10日
1.概述 进程地址空间由每个进程中的线性地址区组成,而且更为重要的特点是内核允许进程使用该空间的地址。进程地址空间中的任何有效地址只能位于惟一的区域,这些内存区域不能相互覆盖,可以看到,在执行进程中,每个不同的内存片段都对应一个独立的内存区域: 栈,对象代码,全局变量,被映射的文件等等。
2. 内存描述符
内核使用内存描述符结构体来表示进程的地址空间。该结构包含了和进程地址空间有关的全部信息。内存描述符由mm_struct 结构体表示,定义在.
struct mm_struct{
struct vm_area_struct *mmap /*内核区域链表*/
struct rb_root
struct vm_area_struct *mmap_cache
pgd_t *pgd
......
}
所有的mm_struct结构体都通过自身的mmlist域连接在一个双向链表中,该链表的首元素是init_mm描述符,它代表init进程的地址空间。在进程的描述符中,current->mm域中存放该进程使用的内存描述符。所以current->mm代表当前进程的内存描述符。
3. 内存区域
内存区域由vm_area_struct结构体描述,定义在中。内存区域在内核中也经常被称为虚拟内存区域VMA。
vm_area_struct 描述了指定地址空间内连续区间上的一个独立内存范围。vm_mm指向和VMA相关的mm_struct结构体,注意每个VMA对其相关的mm_struct结构体来说都是以惟一的,所以即使两个进程将同一个文件映射到各自的地址空间,它们分别都会有一个vm_area_struct结构体来标志自己的内存区域。
VMA标志,VM_READ,VM_WRITE,VM_EXEC标志内存区域的页面读,写和执行权限。这些标志要求组合构成VMA的访问权限。
VMA操作,vm_area_struct 结构体中的vm_ops域指向与指定内存区域相关的操作函数表。内核使用表中的方法操作VMA。
具体的方法如下:
void open(struct vm_area_struct *area);
当一个指定的内存区域被加一个地址空间时,该函数被调用。
void close(struct vm_area_struct *area);
当指定的内存区域从地址空间中删除时,该函数被调用。
struct page* nopage(struct vm_area_struct *area,unsigned long address,int unused);
第二个参数是用户空间的虚拟地址,当访问的页不在物理内存中时,该函数被页错误处理调用。
int populate(struct vm_area_struct *area,unsigned long address,unsigned long len,pgprot_t prot,unsigned long pgoff,int nonblock);
该函数被系统调用remap_pages()调用来为将要发生的缺页中断预映射一个新映射。
mmap()和do_mmap()函数:
内核使用do_mmap()函数来创建一个新的线性地址区间,说该函数创建一个新的VMA并不非常准确,如果创建的地址区间与一个已经存在的地址区间相邻,就会合并。
总之,每个进程对应一个进程区域描述符mm_struct,而虚拟内存区域VMA指定了mm_struct上的一段连续的独立的内存范围。