mm_struct


无论是内核线程还是用户进程,对于内核来说,无非都是 task_struct这个数据结构的一个实例而已,task_struct被称为进程描述符(process descriptor),因为它记录了这个进程所有的context。其中有一个被称为'内存描述符‘(memory descriptor)的数据结构 mm_struct,抽象并描述了Linux视角下管理进程地址空间的所有信息。
mm_struct定义在include/linux/mm_types.h中
其中的域抽象了进程的地址空间,如下图所示:
一、什么是mm_struct?
内存描述符也用一个结构体表示,这个结构体的名字叫做mm_struct(内存描述符),linux就是通过mm_struct这个结构体来实现内存管理。 一个进程的虚拟地址空间主要由两个数据结构来描述,一个是最高层次的mm_struct,一个是较高层次的vm_ares_struct。最高层次的mm_struct结构描述了一个进程的整个虚拟地址空间。较高层次的结构vm_area_struct描述了虚拟地址空间的一个区间(简称虚拟区)。每个进程只有一个mm_struct结构,在每个进程的task_struct结构体中,有一个指向该进程的结构。可以说,mm_struct结构是对整个用户空间的描述。
在进程的task_struct结构体中包含一个指向mm_struct结构的指针,mm_struct用来描述一个进程的虚拟地址空间。进程的mm_struct则包含装入的可执行映像信息以及进程的页目录指针pgd。该结构还包含有指向vm_area_struct结构的几个指针,每个vm_area_struct代表进程的一个虚拟地址区间。vm_area_struct结构含有指向vm_operations_struct结构的一个指针,vm_operations_struct描述了在这个区间的操作。vm_operations_struct结构中包含的是函数指针,其中open、close分别用于虚拟区间的打开、关闭,而nopage用于当虚拟页面不再物理内存而引起的”缺页异常”时所调用的函数,当linux处理这一缺页异常时,就可以为新的虚拟内存分配实际的物理内存。
进入mm_struct命令:
下图就是task_struct mm_struct vm_area_struuct 的地址映射机制:
每个进程都只有一个内存描述符mm_struct。在每个进程的task_struct结构中,有一个指向mm_struct的变量,这个变量常常是mm。
mm_struct是对进程的地址空间(虚拟内存)的描述。一个进程的虚拟空间中可能有多个虚拟区间,对这些虚拟空间的组织方式有两种,当虚拟区较少时采用单链表,由mmap指针指向这个链表,当虚拟区间多时采用红黑树进行管理,由mm_rb指向这棵树。因为程序中用到的地址常常具有局部性,因此,最近一次用到的虚拟区间很可能下一次还要用到,因此把最近用到的虚拟区间结构放到高速缓存,这个虚拟区间就由mmap_cache指向。
指针pgt指向该进程的页目录(每个进程都有自己的页目录),当调度程序调度一个程序运行时,就将这个地址转换成物理地址,并写入控制寄存器。
由于进程的虚拟空间及下属的虚拟区间有可能在不同的上下文中受到访问,而这些访问又必须互斥,所以在该结构中设置了用于P,V操作的信号量mmap_sem。此外,page_table_lock也是为类似的目的而设置。
虽然每个进程只有一个虚拟空间,但是这个虚拟空间可以被别的进程来共享。如:子进程共享父进程的地址空间,而mm_user和mm_count就对其计数。另外,还描述了代码段、数据段、堆栈段、参数段及环境段的起始和结束地址。
下面就是mm_struct内部成员
struct mm_struct {
struct vm_area_struct * mmap; /* 指向VMAs系统列表*/
struct rb_root mm_rb; /*指向red_black树*/
struct vm_area_struct * mmap_cache; /* 指向最近找到的虚拟空间*/
unsigned long (*get_unmapped_area) (struct file *filp,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);
unsigned long (*get_unmapped_exec_area) (struct file *filp,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);
void (*unmap_area) (struct mm_struct *mm, unsigned long addr);
unsigned long mmap_base;
unsigned long task_size;
unsigned long cached_hole_size;
unsigned long free_area_cache;
pgd_t * pgd; /*指向进程的页目录*/
atomic_t mm_users; /* 用户空间中的有多少用户*/
atomic_t mm_count; /* 对"struct mm_struct"有多少引用*/
int map_count; /*虚拟区间个数*/
struct rw_semaphore mmap_sem;
spinlock_t page_table_lock; /* 保护任务页表和mm->rss*/
struct list_head mmlist; /* mm链表的所有活动*/
mm_counter_t _file_rss;
mm_counter_t _anon_rss;
mm_counter_t _swap_usage;
unsigned long hiwater_rss; /*进程所拥有的最大页框数*/
unsigned long hiwater_vm; /* 进程现行区最大页数*/
unsigned long total_vm, locked_vm, shared_vm, exec_vm;/* total_vm 进程地址空间的大小(页数)
locked_vm 锁住而不能换出的页的个数
shared_vm 共享文件内存映射中的页数*/
unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;/* stack_vm 用户堆栈中的页数
reserved_vm 在保留区中的页数或者在特殊线性区中的页数
def_flags 线性区默认的访问标志
nr_ptes 进程的页表数*/
unsigned long start_code, end_code, start_data, end_data; /*start_code 代码段起始地址,
end_code 代码段结束地址,
start_data 数据段起始地址,
start_end 数据段结束地址*/
unsigned long start_brk, brk, start_stack; /*start_brk 和brk记录有关堆的信息,
start_brk是用户虚拟地址空间初始化时堆的结束地址,
brk 是当前堆的结束地址
start_stack 是栈的起始地址*/
unsigned long arg_start, arg_end, env_start, env_end;/* arg_start参数段的起始地址,
arg_end 参数段的结束地址,
env_start 环境段的起始地址,
env_end 环境段的结束地址*/
unsigned long saved_auxv[AT_VECTOR_SIZE]; /* 开始执行ELF程序时会使用到saved_auxv参数 */
struct linux_binfmt *binfmt;
cpumask_t cpu_vm_mask; /* 用于懒惰TLB交换的位掩码*/
mm_context_t context; /* 指向有关特定体系结构信息的表*/
unsigned int faultstamp;
unsigned int token_priority;
unsigned int last_interval;
unsigned long flags; /* 线性区默认的访问标志(访问设置相关位的时候,必须使用原子操作来解决)*/
struct core_state *core_state; /* coredumping support */
union {
unsigned long rh_reserved_aux;
atomic_t oom_disable_count;
};
unsigned long shlib_base;
#endif
};