千家信息网

如何理解Linux进程的内存管理

发表于:2024-11-30 作者:千家信息网编辑
千家信息网最后更新 2024年11月30日,这篇文章给大家介绍如何理解Linux进程的内存管理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。几个关键的数据结构一个进程的虚拟地址空间主要由两个数据结来描述,一个是 mm_st
千家信息网最后更新 2024年11月30日如何理解Linux进程的内存管理

这篇文章给大家介绍如何理解Linux进程的内存管理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

几个关键的数据结构

一个进程的虚拟地址空间主要由两个数据结来描述,一个是 mm_struct,一个是 vm_area_structs。

mm_struct结构描述了一个进程的整个虚拟地址空间,vm_area_truct描述了虚拟地址空间的一个区间(简称虚拟区)。下图就是我们所说的由task_struct到mm_struct,进程的地址空间的分布。

每一个进程都会有自己独立的mm_struct,这样每一个进程都会有自己独立的地址空间,这样才能互不干扰。当进程之间的地址空间被共享的时候,我们可以理解为这个时候是多个进程使用一份地址空间,这就是线程。

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 数据结构来管理,包括虚拟内存的起始和结束地址,以及内存的访问权限等,通常命名为vma;vm_area_struct 数据结构的定义如下:

struct vm_area_struct {  /* The first cache line has the info for VMA tree walking.   第一个缓存行具有VMA树移动的信息*/    unsigned long vm_start;  /* Our start address within vm_mm. */  unsigned long vm_end;  /* The first byte after our end address within vm_mm. */    /* linked list of VM areas per task, sorted by address  每个任务的VM区域的链接列表,按地址排序*/  struct vm_area_struct *vm_next, *vm_prev;    struct rb_node vm_rb;    /*   此VMA左侧最大的可用内存间隙(以字节为单位)。    在此VMA和vma-> vm_prev之间,   或者在VMA rbtree中我们下面的一个VMA与其->vm_prev之间。    这有助于get_unmapped_area找到合适大小的空闲区域。   */  unsigned long rb_subtree_gap;    /* Second cache line starts here.   第二个缓存行从这里开始*/    struct mm_struct *vm_mm; /* 我们所属的address space*/  pgprot_t vm_page_prot;  /* 此VMA的访问权限 */  unsigned long vm_flags;  /* Flags, see mm.h. */    /*   对于具有地址空间(address apace)和后备存储(backing store)的区域,   链接到address_space->i_mmap间隔树,或者链接到address_space-> i_mmap_nonlinear列表中的vma。   */  union {   struct {    struct rb_node rb;    unsigned long rb_subtree_last;   } linear;   struct list_head nonlinear;  } shared;    /*   在其中一个文件页面的COW之后,文件的MAP_PRIVATE vma可以在i_mmap树和anon_vma列表中。   MAP_SHARED vma只能位于i_mmap树中。    匿名MAP_PRIVATE,堆栈或brk vma(带有NULL文件)只能位于anon_vma列表中。   */  struct list_head anon_vma_chain; /* Serialized by mmap_sem & * page_table_lock           由mmap_sem和* page_table_lock序列化*/  struct anon_vma *anon_vma; /* Serialized by page_table_lock 由page_table_lock序列化*/    /* 用于处理此结构体的函数指针 */  const struct vm_operations_struct *vm_ops;    /* 后备存储(backing store)的信息: */  unsigned long vm_pgoff;  /* 以PAGE_SIZE为单位的偏移量(在vm_file中),*不是* PAGE_CACHE_SIZE*/  struct file * vm_file;  /* 我们映射到文件(可以为NULL)*/  void * vm_private_data;  /* 是vm_pte(共享内存) */   #ifndef CONFIG_MMU  struct vm_region *vm_region; /* NOMMU映射区域 */ #endif #ifdef CONFIG_NUMA  struct mempolicy *vm_policy; /* 针对VMA的NUMA政策 */ #endif };

小实验

  • insmod test.ko pid_mem=3253 显示各个vma区域

  • cat /proc/3253/maps 显示各个vma区域

看下两种方式的对比:

关于如何理解Linux进程的内存管理就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0