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

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上的一段连续的独立的内存范围。