Linux的进程地址空间管理

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

内存描述符
内存描述符(续)
内存描述符(再续)
线性区(vm_area_struct)
1. 必须记录进程地址空间中哪些区域被使用了,而哪些区域空 闲。 2. 如果进程地址空间中的一个区域被分配给了进程,则内核会 创建一个对应的线性区,也叫虚拟内存区(VMA) 3. 属于同一个进程地址空间的线性区形成一个链表。 4. 不同的VMA绑定不同的访问权限和属性:可读、可写、可执 行、私有、共享、锁定等。 5. 不同的VMA中存放了不同类型的数据:代码、全局变量、只 读数据、动态库… 6. 为了加速查找空闲虚拟内存区,Linux同时将同一进程的所有 线性区组织成一棵红黑树。 7. 线性区的开始和结束都必须4KB对齐
3. 被映射给进程的物理内存
• • •
2
进程地址空间管理2个原则
1. “先申请,后使用”“不用了,及时释放” 2. 尽量推迟物理内存的分配时机
3
内存描述符(mm_struct)
1. 每个进程都有自己独立的3GB的线性地址空间。该空 间不同的区域有不同的用途:代码区、全局数据区、 栈区、堆区… 2. 与进程地址空间有关的全部信息都包含在一个叫内 存描述符的数据结构中。
Linux虚拟内存管理
进程地址空间
进程地址空间管理:管什么?
1. 管3GB的用户虚拟地址空间:
• • 哪些区域被分配了,哪些区域是空闲的 被分配区域的用途、权限等属性信息
2. 页表的相应部分
• 需要创建映射时再创建页表,不需要时释放页表(而内核 空间对应的页表永不释放)
需要时动态申请,不需要时释放 不要求物理内存必须连续 回收暂时不用的页框(Ch.17)
21
mmap的应用
1. 2. 3. 4. 快速读写大文件,简化程序逻辑。 快速读写I/O设备(如V4L库) 创建进程间共享内存(可利用/dev/zero文件) 在用户态的应用程序中直接读写物理内存(即读写指定物理 地址上的内存单元)。 • /dev/mem是整个物理内存的全映像文件 • open("/dev/mem",O_RDWR|O_SYNC),然后mmap,接着 就可以用mmap的地址来访问物理内存 • 只有root用户才能这样做! • 如果CPU是内存与I/O统一编址方式,还可以利用上述方法 访问外设的寄存器,编写用户态的设备驱动程序。 5. 快速分配大内存(mmap配合MAP_ANONYMOUS 参数)
13
如何实现进程地址空间动态内存分配
1. 查找进程虚拟地址空间是否存在大小合适的空闲区 域。 2. 如果有,则创建相应的线性区描述符vm_area_struct, 并将其插入链表mmap 3. 线性区创建成功后,立即返回(注意,没有分配相 应的物理页框,也没有修改页表!) 4. 当用户程序访问刚刚动态分配的内存时,会触发缺 页异常。 5. 在缺页异常的中断服务程序中按“一次一页”的方 式分配物理页框,并修改页表。
14
增加或删除一个线性区
2015/9/28
Linux OS analysis
15/24Hale Waihona Puke Baidu
处理线性区的函数
内核进程需要对一个线性区进行处理,比如确定一个给 定线性地址是否存在于一个线性地址空间中 find_vma(),查找一个线性地址所属的线性区
两个参数:进程内存描述符的地址mm和线性地址addr
4
相关的数据结构
1. task_struct用于描述一个进程, task_struct中有一个字段:
struct mm_struct *mm;
2. mm_struct用于描述一个进程虚拟地址空间的布局。 mm_struct 中有一个字段mmap,指向了一个链表。
struct vm_area_struct *mmap
22
缺页异常(14号中断)
23
缺页异常(14号中断)
24
static inline unsigned long do_mmap (struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flag, unsigned long offset)
find_vma_intersection(),查找一个与给定地址区间重叠 的线性区 get_unmapped_area(),查找一个空闲的地址区间 insert_vm_struct(),向内存描述符链表中插入一个线性区 split_vma(),拆分线性区
创建一个线性区间
mmap()和do_mmap(),创建一个线性区
include/linux/mm.h

根据file参数映射指定的文件中偏移量为offset,长度为len的一段内容 addr参数指明从何处开始查找一段可用的空闲线性地址区间 Prot参数指定这个区间所包含的页的存取权限 flags参数指定这个创建的线性区本身的一些标志
删除一个线性区间
munmap()和do_munmap()
10
Virtual Memory Areas
与进程地址空间相关的数据结构
mm_struct
触发进程空间的内存动态分配的操作
1. 进程创建:fork,execv,clone 2. 扩充/紧缩堆内存:brk, sbrk 3. 创建文件内存映射或匿名映射:mmap, mremap, munmap 4. 创建进程间共享内存:shmat, shmdt 5. 当用户堆栈不够用的时候,需要扩展堆栈 6. 上述操作都可能引起线性区数据结构的创建和删除。
20
mmap内存映射
1. int munmap(void *start, size_t length) 取消映射关系 2. int msync(const void *start, size_t length, int flags) 将内存中的内容同步到文件
思考:
mmap函数执行时会一次性将整个被映射文件读入内存吗? 即用mmap函数映射一个大文件时会很耗时吗?

int
start:要映射到的虚拟内存区域的起始地址,通常都是用NULL, NULL表示由内核来指定该内存地址 • length:要映射的内存区域的大小 • prot:期望的内存保护标志,是以下的某个值,可以通过or运算符组合 到一起 1. PROT_EXEC 可执行;2. PROT_READ可读;3. PROT_WRITE可执 • flags:指定映射对象的类型,映射选项和映射页是否可以共享。 MAP_SHARED /MAP_PRIVATE/MAP_LOCKED/ MAP_ANONYMOUS • fd:文件描述符(由open函数返回) • offset:表示被映射对象(即文件)从那里开始对映,通常都是用0。 该值应该为大小应为PAGE_SIZE的整数倍 • 返回值:成功则返回被映射虚拟内存区的指针,失败返回-1。
mmap内存映射
1. 利用mmap函数可以将一个磁盘文件或者其它设备对象映射到 虚拟内存空间。文件被映射到多个页上,所有页的大小之和 大于等于文件大小。
19
mmap内存映射
1. void * mmap(void *start, size_t length, int prot , int flags, fd, off_t offset)
3. mmap链表中的一个节点vm_area_struct记录了实际分配的一个 内存区域。
5
进程描述符(task_struct)
struct task_struct { /* these are hardcoded - don't touch */ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ long counter; long priority; …. … … … … /* filesystem information */ struct fs_struct *fs; /* open file information */ struct files_struct *files; /* memory management info */ struct mm_struct *mm; …. … … … … }
mm/mmap.c
do_munmap()函数从进程地址空间中删除一段线性空 间
int do_munmap (struct mm_struct *mm, unsigned long addr, size_t len)
mm参数指向了当前进程的内存描述符 addr参数为线性区的起始地址 len参数指明要删除的区间大小
相关文档
最新文档