概述
linux内核除了需要管理自身的内存,还需要管理用户空间进程的内存----------进程地址空间。linux内核采用虚拟内存技术,系统中的所有进程之间以虚拟方式共享内存。对一个进程而言,它好像可以访问整个系统的所有物理内存。
一、地址空间
进程地址空间由进程可寻址的虚拟内存组成。现代采用虚拟内存的操作系统通常都使用平坦地址空间而不是分段式的内存模式。
内存地址4021f000表示的是进程32位地址空间中的一个特定字节,尽管一个进程可以寻址4GB的虚拟内存,但我们只关心有权访问的地址区间如08048000-0804c000,这些可被访问的合法地址空间称为内存区域。进程可以增加或减少自己的内存区域。进程地址空间中的任何有效地址都只能位于唯一的区域,内存区域之间不能相互覆盖。
内存区域包含内存对象,如:
- 可执行文件代码的内存映射,即代码段;
- 可执行文件的已初始化全局变量的内存映射,即数据段;
- 未初始化全局变量,即bss段的零页;
- 用于进程的用户空间栈的零页的内存映射;
- C库或动态链接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间;
- 任何内存映射文件;
- 任何共享内存段;
- 任何匿名的内存映射,如malloc分配的内存;
二、内存描述符----进程地址空间
该结构包含和进程相关的全部信息,在进程的进程描述符中,mm域存放进程的内存描述符,current->mm指向当前进程的内存描述符。内存描述符由mm_struct表示,每个进程都有唯一的mm_struct结构体,即唯一的进程地址空间。
进程地址空间包含多个内存区域,其中mmap和mm_rb两个数据结构体描述的对象就是该地址空间中的全部内存区域。分别以链表形式和红黑树形式存放。
mm_struct结构体通过自身的mmlist域连接在一个双向链表中,该链表的首元素是init_mm内存描述符,代表init进程的地址空间。
内核线程没有进程地址空间,但访问内核内存还是需要用到如页表之类的数据。为了避免内核线程为内存描述符和页表浪费内存,也为避免当内核线程运行时,浪费处理器周期向新地址空间进行切换,内核线程直接使用前一个进程的内存描述符。
分配进程地址空间:allocate_mm()
撤销进程地址空间:exit_mm()–>mmput()–>mmdrop()–>free_mm()
三、虚拟内存区域
进程地址空间内连续区间上的一个独立内存范围成为虚拟内存区域,由vm_area_struct结构体描述。每个vma可以代表不同类型的内存区域,如内存映射文件或进程用户空间栈。
VMA操作
**void open(struct vm_area_struct area) #将指定内存区域加入到一个地址空间
**void close(struct vm_area_struct area)#将指定内存区域从一个地址空间删除
*int fault(struct vm_area_struct *area,struct vm_fault *vmf) #被访问页面没有出现在物理内存区域,页面故障处理调用该函数
*int page_mkwrite(struct vm_area_struct *area,struct vm_fault *vmf) #访问只读也面试,页面故障处理调用该函数
*int access(struct vm_area_struct *vma,unsigned long address,void *buf,int len,int write) #当get_user_pages()调用失败时,access_process_vm()函数调用该函数
找到一个给定的内存地址属于哪一个内存区域
struct vm_area_struct *find_vma(struct mm_struct *mm,unsigned long addr);
struct vm_area_struct *find_vma_prev(struct mm_struct *mm,unsigned long addr,struct vm_area_struct **pprev);
struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
unsigned long start_addr,
unsigned long end_addr)
创建地址区间
unsigned long do_mmap(struct file *file,unsigned long addr,
unsigned long len,unsigned long prot,
unsigned long flag,unsigned long offset)
删除地址区间
unsigned long do_munmap(struct mm_struct *mm,unsigned long start,size_t len)
四、页表
应用程序访问虚拟地址时,首先必须将虚拟地址转化成物理地址,然后处理器才能解析地址访问请求。
地址的转换工作通过查询页表完成,即将虚拟地址分段,使每段虚拟地址作为一个索引指向页表,而页表项则指向下一级别的页表或最终的物理页面。linux采用三级页表完成地址转换,可节约地址转换需占用的存放空间。
顶级页表是页全局目录(PGD)
二级页表是中间页目录(PMD)
最后一级页表简称页表(pte_t)
最后
以上就是彩色香氛为你收集整理的进程地址空间的全部内容,希望文章能够帮你解决进程地址空间所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复