理解task_struct, mm_struct, 和vm_area_struct之间的关系。
即是理解进程,进程地址空间和VMA之间的关系
进程地址空间
进程地址空间是指进程可以寻址的虚拟地址空间。
32位的处理器中,进程可以虽然寻址4G虚拟地址空间,但是内存空间用户无权访问。
把用户有权访问的地址空间称为内存区域
内存区域
每个进程都有一套自己的页表,所以即使两个进程访问的虚拟地址相同,经过不同的页表转换之后,他们实际访问到的物理地址还是不同的。
内存区域规划
用户进程的栈 |
---|
mmap映射区域 |
堆映射区域 |
数据段映射 |
代码段映射 |
内存区域管理结构体
struct mm_struct 管理的是这个进程的整个内存区域
struct vm_area_struct (VMA)管理的是内存区域中的其中一段映射,例如代码段映射
所有struct vm_area_struct 形成一个链表和一颗红黑树,链表头和红黑数根结点在struct mm_struct 中。
malloc就是从内存区域中分一块VMA出来
遍历一个进程中所有的VMA
以下这个代码可以帮助理解task_struct, mm_struct, 和vm_area_struct之间的关系。
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
static int pid;
module_param(pid, int, S_IRUGO);
static void printit(struct task_struct *tsk)
{
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long start, end, length;
int i = 0;
mm = tsk-> mm;
vma = mm->mmap;
down_read(&mm->mmap_sem);
while(vma) {
start = vma->vm_start;
end = vma->vm_end;
length = end -start;
printk("%d: vma->start = 0x%lx, vma->vma_end = 0x%lx length = 0x%lx \n",
i, start, end, length);
vma = vma->vm_next;
i++;
}
up_read(&mm->mmap_sem);
}
static int __init my_init(void)
{
struct task_struct *tsk;
if( pid == 0 ){
tsk = current;
pid = current->pid;
} else {
tsk = pid_task(find_vpid(pid), PIDTYPE_PID);
}
if( !tsk )
return -1;
printk("Examing vma's for pid = %d, command = %s\n", pid, tsk->comm);
printit(tsk);
return 0;
}
static void __exit my_exit(void)
{
printk("byebye\n");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhouhan");
MODULE_DESCRIPTION("get physpages");
MODULE_ALIAS("han phypages get");
用户态对进程地址空间的操作
malloc是用户态常用的分配内存接口的函数,mmap是用户台常用的用于建立文件映射或匿名映射的函数,这两个函数都是在进程地址空间中进行操作。