mm_struct简介

本文介绍了Linux内核中的mm_struct结构,它是用于描述进程虚拟地址空间的关键数据结构。每个进程有一个mm_struct,包含页目录指针、虚拟区间描述符vm_area_struct的链表或红黑树,以及用于同步和计数的信号量。vm_area_struct表示虚拟空间的特定区域,而vm_operations_struct定义了在这些区域上的操作,如打开、关闭和处理缺页异常。

一、什么是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处理这一缺页异常时,就可以为新的虚拟内存分配实际的物理内存。

下面的linux管理内存的大致结构:
这里写图片描述

二、mm_struct
每个进程都只有一个内存描述符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就对其计数。
另外,还描述了代码段、数据段、堆栈段、参数段及环境段的起始和结束地址。

struct mm_struct
{
     struct vm_area_struct *mmap;    //指向虚拟区间(VMA)链表
     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 pgoof,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;
     unsigned long hiwter_rss;
     unsigned long hiwater_vm;


     unsigned long total_vm,locked_vm,shared_vm,exec_vm;
     usingned long stack_vm,reserved_vm,def_flags,nr_ptes;

     unsingned long start_code,end_code,start_data,end_data;  //代码段的开始start_code ,结束end_code,数据段的开始start_data,结束end_data

     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];

     struct linux_binfmt *binfmt;

     cpumask_t cpu_vm_mask;
     mm_counter_t context;
     unsigned int faultstamp;
     unsigned int token_priority;
     unsigned int last_interval;

     unsigned long flags;
     struct core_state *core_state;
}

三、vm_area_struct
虚拟地址区间vm_area_struct是虚拟内存的一部分,内存描述符mm_struct指向整个虚拟空间,而vm_area_struct只是指向了虚拟空间的一段。较高层次的结构vm_area_struct是由双向链表链接起来的,它们是按照虚拟地址降序排序的,每个这样的结构都对应描述一个相邻的地址空间范围。之所以这样分隔是因为每个虚拟区间可能来源不同,有的可能来自可执行映像,有的可能来自共享库,而有的可能是动态内存分配的内存区,所以对于每个由vm_area_struct结构所描述的区间的处理操作和它前后范围的处理操作不同,因此linux把虚拟内存分割管理,并利用了虚拟内存处理例程vm_ops来抽象对不同来源虚拟内存的处理方法。不同的虚拟区间其处理操作可能不同,linux在这里利用了面向对象的思想,即把一个虚拟区间看成是一个对象,用vm_area_struct描述这个对象的属性,其中的vm_operation结构描述了在这个对象上的操作。

struct vm_area_struct
{
     struct mm_struct *vm_mm;       //虚拟地址区间所在的地址空间
     unsigned long vm_start;        //在vm_mm中的起始地址
     unsigned long vm_end;          //在vm_mm中的结束地址

     struct vm_area_struct *vm_next; //指向下一个虚拟区间
     pgprot_t vm_page_prot;          //虚拟区间的存取极限
     unsigned long vm_flags;         //描述对虚拟区间进行操作的标志
     struct rb_node vm_rb;           

     union
    {
            struct 
    {
        struct list_head list;
        void *parent;
        struct vm_area_struct *head;
     } vm_set;

     struct raw_prio_tree_node prio_tree_node;

   } shared;

struct list_head anon_vma_node;
struct anon_vma *anon_vma;

const struct vm_operations_struct *vm_ops;   //对这个区间进行操作的函数

unsigned long vm_pgoff;
struct file* vm_file;
void *vm_private_data;
unsigned long vm_truncate_count;
}

四、vm_operations_struct
vm_operations_struct结构中包好的是函数指针,其中open、close分别用于虚拟内存的打开、关闭,而nopage用于当虚拟内存页面没有实际的物理内存映射而引起的”缺页异常”时所调用的函数指针。

struct vm_operations_struct
{
     void (*open)(struct vm_area_strucr *area);
     void (*close)(struct vm_area_struct *area);
     struct page *(nopage)(struct vm_area_struct *area,unsigned long address,int unused);
}

五、linux虚拟内存管理数据结构图(本来想自己画的,结果发现这个图真的不错,所以直接粘过来):
这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值