进程描述结构 task_struct中包含下列成员
struct mm_struct *mm, *active_mm;
每个进程描述符都包含: mm和active__mm,其中mm成员指向进程拥有的内存描述符,而active_mm则指向当前正在执行的内存描述符。
对于普通进程来说,二者是一样的;但是对于kernel线程没有内存描述符,mm为空,active_mm指向前一个执行进程的mm。
mm_struct
该结构保存了进程的内存管理信息
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
vm_area_struct
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_mm:内存区所属的地址空间
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:指向许多方法的集合,这些方法用于在内存区上执行各种标准操作。
- 在创建和删除内存区域时,会分别调用open close函数。一般我们设置为NULL,表示不使用这个接口。
- fault是最终要的一个方法,当访问地址空间的某个虚拟地址时,还没有做物理内存映射(或者是没有page没有写权限),自动触发的缺页异常管理最终会调用到该函数。这个函数会处理地址映射,数据读取,copy on write.
vm_pgoffset:指定了文件映射的偏移量,该值只用于映射了文件部分内容时(如果映射了整个文件,那么偏移量为0)
vm_file:指向映射文件的file object的指针,如果vm映射的是一个文件。如果映射的对象不是文件爱你,否则为NULL
vm_private_data:用于存储私有数据,不由通用内存管理程序操作。