一:进程地址空间
1.内核使用内存描述符结构体表示进程的地址空间,该结构体包含了和进程地址空间有关的全部信息。内存描述符由mm_struct()结构体表示。在struct task_struct()中有一个struct mm_struct()*的指针指向该结构体。
2.Mm_struct()结构体中包括的域有
(1)struct vm_area_struct *mmap指向一个链表,虚拟内存的线性空间有多少个区间就有多少个struct vm_area_struct结构体
- struct vm_area_struct结构中有vm_start和vm_end代表一个区间的起始和结束位置,以及下一个链表节点指向下一个struct vm_area_struct结构体
- Cat /proc/pid/maps 查看当前pid的进程对应线性区间
- 虽然书上说每个段有一个 但是利用以上指令查看 每个段并非真的 只有一个但是还会根据权限不同而继续划分
- 通过查看struct mm_struct()结构体看到有两个struct vm_area_struct结构体指针,第二个该结构体的指针保存的是最后使用的内存区域的地址,作用是记录上次访问的,当重新访问的是上次周围的内存区域时,效率更高
(2)struct rb_root:与struct vm_area_struct描述的对象是相同的,不过该结构体用红黑树的形式组织存放而struct vm_area_struct以链表的形式组织存放,搜索红黑树的时间复杂度时O(logn)。
内核通常会避免使用两种数据结构组织同一种数据结构,但是此处的冗余派的上用场,mmap结构体作为链表,有利于简单高效的遍历所有元素,而mm_rb结构体作为红黑树,更适合搜索指定元素。
(3)mm_users域:记录正在使用该地址的进程数目。一般来说一个进程对应一个PCB,一个PCB中有一个内存描述符mm_struct,即地址空间,所以对进程来说该值一般为1,但是当n个进程共享这一个地址空间时,那么该值就等于n。此时这些进程也称为线程。
(4)mm_count域:主使用计数,只要mm_users不为0,那么mm_count值就为1.当mm_users的值减为0时mm_count才为0,说明已经没有任何指向mm_struct结构体的引用,这时,该结构体就会被销毁。
在fork的copy_mm()函数中就有
(5)pgd_t类型的*pgd指向的是页全局目录,也就是根页表
3.分配内存描述符
在fork源码中有当新线程域父进程共享地址空间时只需要让新线程中的struct mm_struct * mm指向父进程的地址空间即可。不一样时才会申请新的进程描述符,并拷贝父进程内存地址空间中的内容