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)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)