进程描述结构 task_struct中包含下列成员
struct mm_struct *mm, *active_mm;
每个进程描述符都包含: mm和active__mm,其中mm成员指向进程拥有的内存描述符,而active_mm则指向当前正在执行的内存描述符。
对于普通进程来说,二者是一样的;但是对于kernel线程没有内存描述符,mm为空,active_mm指向前一个执行进程的mm。
该结构保存了进程的内存管理信息
156 struct mm_struct { 157 struct vm_area_struct * mmap; /* list of VMAs */ 158 struct rb_root mm_rb; 159 struct vm_area_struct * mmap_cache; /* last find_vma result */ 160 unsigned long (*get_unmapped_area) (struct file *filp, 161 unsigned long addr, unsigned long len, 162 unsigned long pgoff, unsigned long flags); 163 void (*unmap_area) (struct mm_struct *mm, unsigned long addr); 164 unsigned long mmap_base; /* base of mmap area */ 165 unsigned long task_size; /* size of task vm space */ 166 unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ 167 unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ 168 pgd_t * pgd; 169 atomic_t mm_users; /* How many users with user space? */ 170 atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ 171 int map_count; /* number of VMAs */ 172 struct rw_semaphore mmap_sem; 173 spinlock_t page_table_lock; /* Protects page tables and some counters */ 174 175 struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung 176 * together off init_mm.mmlist, and are protected 177 * by mmlist_lock 178 */ 179 180 /* Special counters, in some configurations protected by the 181 * page_table_lock, in other configurations by being atomic. 182 */ 183 mm_counter_t _file_rss; 184 mm_counter_t _anon_rss; 185 186 unsigned long hiwater_rss; /* High-watermark of RSS usage */ 187 unsigned long hiwater_vm; /* High-water virtual memory usage */ 188 189 unsigned long total_vm, locked_vm, shared_vm, exec_vm; 190 unsigned long stack_vm, reserved_vm, def_flags, nr_ptes; 191 unsigned long start_code, end_code, start_data, end_data; 192 unsigned long start_brk, brk, start_stack; 193 unsigned long arg_start, arg_end, env_start, env_end; 194 195 unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ 196 197 cpumask_t cpu_vm_mask; 198 199 /* Architecture-specific MM context */ 200 mm_context_t context; 201 202 /* Swap token stuff */ 203 /* 204 * Last value of global fault stamp as seen by this process. 205 * In other words, this value gives an indication of how long 206 * it has been since this task got the token. 207 * Look at mm/thrash.c 208 */ 209 unsigned int faultstamp; 210 unsigned int token_priority; 211 unsigned int last_interval; 212 213 unsigned long flags; /* Must use atomic bitops to access the bits */ 214 215 /* coredumping support */ 216 int core_waiters; 217 struct completion *core_startup_done, core_done; 218 219 /* aio bits */ 220 rwlock_t ioctx_list_lock; 221 struct kioctx *ioctx_list; 222 };
mem_base:表示虚拟地址空间中用于地址映射的区域,早期mmap是从mem_base向上增长的,最终和stack会合;当前引入了一种新布局,mmap可以从mem_base向下增长,最终和對会和。
start_code, end_code 定义了代码的起始地址,和结束地址。start_code和end_code在进程生命周期中不会变化。
start_data, end_data定义了已初始化数据区起始地址和结束地址。start_data和end_data在进程生命周期中不会变化。
start_brk, brk 定义了堆区域的起始地址和结束地址,start_brk在进程生命周期中不会发生变化,brk会随着堆的扩大和缩小而变化。
arg_start, arg_end保存参数列表,位于栈中最高的地址区域
env_start, env_end保存环境变量,位于栈中最高的地址区域。
task_size:进程的地址空间长度,不包括kernel部分。
get_unmapped_area:这个函数搜索进程地址空间,找到一个可用的线性地址区。这个函数会区分两种情况:文件内存映射和匿名内存映射。
描述虚拟地址空间的内存区域:
mmap:虚拟内存区单链表,进程所有的虚拟内存区都会链接到这个单链表中
mm_rb:虚拟内存区红黑树的根节点。
map_cache:最后一次fina_vma的查找结果,根据局部性理论,下一次访问有很大可能还发生在这个区域内。
map_count:内存映射区数目,最大数目限制是sysctl_max_map_count, 65536
虚拟内存使用统计
rss:分配给进程的物理页框数目。又称为驻留内存数目。
anon_rss:分配给进程的匿名内存映射页框数
total_vm:进程使用的地址空间页面数,这个总数是虚拟内存的数目。这个数目应该就是ps 命令中的的VSS列
locked_vm:通过mlock系统调用,锁定住的虚拟内存页数,这部分页面一旦映射后是无法交换出来的。注意,这个数目是虚拟地址页面数,而不是物理页面数
shared_vm:文件共享映射虚拟内存数,只要是文件映射,都会计入这个统计数。
exec_vm:如果内存映射是文件映射,并且是可执行部分,那么统计到这个值中
stack_vm:进程栈空间的虚拟页面大小,初始值为1个页面,扩展stack会增加stack_vm
reserved_vm:
其他成员
pgd:当前进程的页表
mm_users:表示使用这个mm结构的线程数目,比如有两个线程使用它,那么值为2。
mm_count:mm结构的使用计数,为0表示没有使用者,可以释放。由于mm结构可能被内核线程借用,那么为了保证借用期间不会导致被释放,所以会对mm_count加1;此外mm的线程共用一个使用计数,也就是说mm_users大于1只会使mm_count加1
mmlist:所有的mm都链接到一个双向链表上,并通过mmlist链接到一起,这个list的地一个节点是init_mm.mmlist,也就是进程0的内存描述符
mmlist_lock:用来保护mmlist的spin lock
kernel使用vm_area_struct表示一个内存区域
93 /* 94 * This struct defines a memory VMM memory area. There is one of these 95 * per VM-area/task. A VM area is any part of the process virtual memory 96 * space that has a special rule for the page-fault handlers (ie a shared 97 * library, the executable area etc). 98 */ 99 struct vm_area_struct { 100 struct mm_struct * vm_mm; /* The address space we belong to. */ 101 unsigned long vm_start; /* Our start address within vm_mm. */ 102 unsigned long vm_end; /* The first byte after our end address 103 within vm_mm. */ 104 105 /* linked list of VM areas per task, sorted by address */ 106 struct vm_area_struct *vm_next; 107 108 pgprot_t vm_page_prot; /* Access permissions of this VMA. */ 109 unsigned long vm_flags; /* Flags, listed below. */ 110 111 struct rb_node vm_rb; 112 113 /* 114 * For areas with an address space and backing store, 115 * linkage into the address_space->i_mmap prio tree, or 116 * linkage to the list of like vmas hanging off its node, or 117 * linkage of vma in the address_space->i_mmap_nonlinear list. 118 */ 119 union { 120 struct { 121 struct list_head list; 122 void *parent; /* aligns with prio_tree_node parent */ 123 struct vm_area_struct *head; 124 } vm_set; 125 126 struct raw_prio_tree_node prio_tree_node; 127 } shared; 128 129 /* 130 * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma 131 * list, after a COW of one of the file pages. A MAP_SHARED vma 132 * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack 133 * or brk vma (with NULL file) can only be in an anon_vma list. 134 */ 135 struct list_head anon_vma_node; /* Serialized by anon_vma->lock */ 136 struct anon_vma *anon_vma; /* Serialized by page_table_lock */ 137 138 /* Function pointers to deal with this struct. */ 139 struct vm_operations_struct * vm_ops; 140 141 /* Information about our backing store: */ 142 unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE 143 units, *not* PAGE_CACHE_SIZE */ 144 struct file * vm_file; /* File we map to (can be NULL). */ 145 void * vm_private_data; /* was vm_pte (shared mem) */ 146 unsigned long vm_truncate_count;/* truncate_count or restart_addr */ 147 148 #ifndef CONFIG_MMU 149 atomic_t vm_usage; /* refcount (VMAs shared if !MMU) */ 150 #endif 151 #ifdef CONFIG_NUMA 152 struct mempolicy *vm_policy; /* NUMA policy for the VMA */ 153 #endif 154 };
vm_start:在内存去地址空间内的起始地址
vm_end:在内存区地址空间的结束地址
vm_next:进程地址空间包含一个内存区单链表,所有的内存区都会通过这个单链表链接起来,表头是mm->mmap
vm_page_prot:由vm_flags生成。vm_page_prot使用来设置pte页表项的保护位的,不同的体系结构,pte保护位设置方法不同。
vm_flags:存储内存区的属性,包括以下标志位
VM_READ, VM_WRITE, VM_EXEC和VM_SHARED用来标识页面内容是否有读,写,执行,以及是否可以被几个进程共享。
VM_MAYREAD, VM_MAYWRITE, VM_MAYEXEC和VM_MAYSHARE决定是否VM_READ, VM_WRITE, VM_EXEC, VM_SHARED可以被设置。在执行系统调用mprotext时会检查这个标志。
VM_GROWNSDOWN, VM_GROWSUP 指明这个内存区的增长方向。heap是从下向上增长的,所以设置为VM_GROWSUP;而stack是从上向下增长的,所以设置为VM_GROWSDOWN
VM_DONTCOPY,在执行fork系统调用时,内存区不会被copy
VM_DONTEXPAND,禁止使用mremap系统调用扩展这个内存区
VM_HUGETLB,在某些架构下,内存区是使用huge pages进行管理的,此时会设置这个标记。
vm_rb,内存区通过这个节点挂接到进程地址空间的红黑树上。
anon_vma_node和anon_vma
vm_ops:指向许多方法的集合,这些方法用于在内存区上执行各种标准操作。
vm_pgoffset:指定了文件映射的偏移量,该值只用于映射了文件部分内容时(如果映射了整个文件,那么偏移量为0)
vm_file:指向映射文件的file object的指针,如果vm映射的是一个文件。如果映射的对象不是文件爱你,否则为NULL
vm_private_data:用于存储私有数据,不由通用内存管理程序操作。