浅析Linux进程的内存管理

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

[[388230]]

本文转载自微信公众号「人人都是极客」,作者布道师Peter。转载本文请联系人人都是极客公众号。   

几个关键的数据结构

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

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

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

  1. struct mm_struct 
  2.      struct vm_area_struct *mmap;    //指向虚拟区间(VMA)链表 
  3.      struct rb_root mm_rb;           //指向red_black树 
  4.      struct vm_area_struct *mmap_cache;    //找到最近的虚拟区间 
  5.  
  6.      unsigned long(*get_unmapped_area)(struct file *filp,unsigned long addr,unsigned long len,unsigned long pgoof,unsigned long flags); 
  7.  
  8.      void (*unmap_area)(struct mm_struct *mm,unsigned long addr); 
  9.  
  10.      unsigned long mmap_base; 
  11.  
  12.      unsigned long task_size;   //拥有该结构体的进程的虚拟地址空间的大小 
  13.      unsigned long cached_hole_size; 
  14.      unsigned long free_area_cache; 
  15.  
  16.      pgd_t *pgd;  //指向页全局目录 
  17.  
  18.      atomic_t mm_users;         //用户空间中有多少用户 
  19.      atomic_t mm_count;         //对"struct mm_struct"有多少引用 
  20.  
  21.      int map_count;            //虚拟区间的个数 
  22.      struct rw_semaphore mmap_sem; 
  23.      spinlock_t page_table_lock;       //保护任务页表和mm->rss 
  24.  
  25.      struct list_head mmlist;          //所有活动mm的链表 
  26.      mm_counter_t _file_rss; 
  27.      mm_counter_t _anon_rss; 
  28.      unsigned long hiwter_rss; 
  29.      unsigned long hiwater_vm; 
  30.  
  31.  
  32.      unsigned long total_vm,locked_vm,shared_vm,exec_vm; 
  33.      usingned long stack_vm,reserved_vm,def_flags,nr_ptes; 
  34.  
  35.      unsingned long start_code,end_code,start_data,end_data;  //代码段的开始start_code ,结束end_code,数据段的开始start_data,结束end_data 
  36.  
  37.      unsigned long start_brk,brk,start_stack;    //start_brk和brk记录有关堆的信息,start_brk是用户虚拟地址空间初始化,brk是当前堆的结束地址,start_stack是栈的起始地址 
  38.  
  39.      unsigned long arg_start,arg_end,env_start,env_end;     //参数段的开始arg_start,结束arg_end,环境段的开始env_start,结束env_end 
  40.      unsigned long saved_auxv[AT_VECTOR_SIZE]; 
  41.  
  42.      struct linux_binfmt *binfmt; 
  43.  
  44.      cpumask_t cpu_vm_mask; 
  45.      mm_counter_t context; 
  46.      unsigned int faultstamp; 
  47.      unsigned int token_priority; 
  48.      unsigned int last_interval; 
  49.  
  50.      unsigned long flags; 
  51.      struct core_state *core_state; 

分配的每个虚拟内存区域都由一个vm_area_struct 数据结构来管理,包括虚拟内存的起始和结束地址,以及内存的访问权限等,通常命名为vma;vm_area_struct 数据结构的定义如下:

  1. struct vm_area_struct { 
  2.  /* The first cache line has the info for VMA tree walking.  
  3.  第一个缓存行具有VMA树移动的信息*/ 
  4.   
  5.  unsigned long vm_start;  /* Our start address within vm_mm. */ 
  6.  unsigned long vm_end;  /* The first byte after our end address within vm_mm. */ 
  7.   
  8.  /* linked list of VM areas per task, sorted by address 
  9.  每个任务的VM区域的链接列表,按地址排序*/ 
  10.  struct vm_area_struct *vm_next, *vm_prev; 
  11.   
  12.  struct rb_node vm_rb; 
  13.   
  14.  /* 
  15.   此VMA左侧最大的可用内存间隙(以字节为单位)。  
  16.   在此VMA和vma-> vm_prev之间, 
  17.   或者在VMA rbtree中我们下面的一个VMA与其->vm_prev之间。  
  18.   这有助于get_unmapped_area找到合适大小的空闲区域。 
  19.   */ 
  20.  unsigned long rb_subtree_gap; 
  21.   
  22.  /* Second cache line starts here.  
  23.  第二个缓存行从这里开始*/ 
  24.   
  25.  struct mm_struct *vm_mm; /* 我们所属的address space*/ 
  26.  pgprot_t vm_page_prot;  /* 此VMA的访问权限 */ 
  27.  unsigned long vm_flags;  /* Flags, see mm.h. */ 
  28.   
  29.  /* 
  30.   对于具有地址空间(address apace)和后备存储(backing store)的区域, 
  31.   链接到address_space->i_mmap间隔树,或者链接到address_space-> i_mmap_nonlinear列表中的vma。 
  32.   */ 
  33.  union { 
  34.   struct { 
  35.    struct rb_node rb; 
  36.    unsigned long rb_subtree_last; 
  37.   } linear; 
  38.   struct list_head nonlinear; 
  39.  } shared; 
  40.   
  41.  /* 
  42.   在其中一个文件页面的COW之后,文件的MAP_PRIVATE vma可以在i_mmap树和anon_vma列表中。 
  43.   MAP_SHARED vma只能位于i_mmap树中。  
  44.   匿名MAP_PRIVATE,堆栈或brk vma(带有NULL文件)只能位于anon_vma列表中。 
  45.   */ 
  46.  struct list_head anon_vma_chain; /* Serialized by mmap_sem & * page_table_lock 
  47.           由mmap_sem和* page_table_lock序列化*/ 
  48.  struct anon_vma *anon_vma; /* Serialized by page_table_lock 由page_table_lock序列化*/ 
  49.   
  50.  /* 用于处理此结构体的函数指针 */ 
  51.  const struct vm_operations_struct *vm_ops; 
  52.   
  53.  /* 后备存储(backing store)的信息: */ 
  54.  unsigned long vm_pgoff;  /* 以PAGE_SIZE为单位的偏移量(在vm_file中),*不是* PAGE_CACHE_SIZE*/ 
  55.  struct file * vm_file;  /* 我们映射到文件(可以为NULL)*/ 
  56.  void * vm_private_data;  /* 是vm_pte(共享内存) */ 
  57.   
  58. #ifndef CONFIG_MMU 
  59.  struct vm_region *vm_region; /* NOMMU映射区域 */ 
  60. #endif 
  61. #ifdef CONFIG_NUMA 
  62.  struct mempolicy *vm_policy; /* 针对VMA的NUMA政策 */ 
  63. #endif 
  64. }; 

小实验

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

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

看下两种方式的对比:

 

 

责任编辑:武晓燕 来源: 人人都是极客
相关推荐

2022-06-01 16:01:58

MySQL内存管理系统

2009-01-16 09:58:07

C#编程C#内存管理垃圾收集

2023-03-02 23:50:36

Linux进程管理

2011-09-27 09:50:46

软件项目管理

2014-08-01 15:38:37

Linux进程管理

2020-07-07 07:57:39

Linux内存碎片化

2018-05-18 08:43:27

Linux内存空间

2011-01-11 13:47:27

Linux管理进程

2023-03-05 16:12:41

Linux进程线程

2013-10-11 17:32:18

Linux运维内存管理

2017-01-18 21:57:14

2010-02-25 10:28:43

Linux进程管理

2017-08-14 13:35:36

Linux共享内存tmpfs文件系统

2021-05-27 05:28:18

Linux 内存管理

2009-12-25 15:24:16

内存管理

2020-07-28 08:10:33

Linux内存虚拟

2018-11-01 10:59:52

Linux内存进程

2024-01-08 08:42:43

2018-01-12 14:35:00

Linux进程共享内存

2010-02-04 09:26:34

Linux vmsta
点赞
收藏

51CTO技术栈公众号