关于mm_users字段和mm_count字段
mm_users字段存放共享mm_struct数据结构的轻量级进程的个数。mm_count字段是内存描述符的主使计数器,在mm_users次使用计数器中的所有用户在mm_count中只作为一个单位,每当mm_count递减时,内核都要检查他是否变为0,如果是,就要解除这个内存描述符,因为不再有用户使用他。
用一个例子解释mm_users和mm_count之间的不同。考虑一个内存描述符由两个轻量级进程共享。他的mm_users字段通常存放的值为2,而mm_count字段存放的值为1(两个所有者进程算作一个)。如果把内存描述符在一个长操作的中间不被释放,那么,就应该增加mm_users字段而不是mm_count字段的值。最终结果是相同的,因为mm_users的增加确保了mm_count不变为0,即使拥有这个内存描述符的所有轻量级进程全部死亡。
内核线程仅运行在内核态,因此,他们永远不会访问低于TASK_SIZE(等于PAGE_OFFSET,通常为0xc0000000)的地址。与普通进程相反,内核线程不用线性区,因此,内存描述符的很多字段对内核线程是没有意义的。也就是说,当创建内核线程时,内核线程的active_mm共享父进程的mm,但是只使用mm中部分数据与变量。
线性区
linux通过类型为vm_area_struct的对象实现线性区,它的字段为
/*
* This struct defines a memory VMM memory area. There is one of these
* per VM-area/task. A VM area is any part of the process virtual memory
* space that has a special rule for the page-fault handlers (ie a shared
* library, the executable area etc).
*/
structvm_area_struct {
structmm_struct * vm_mm;/* The address space we belong to. */
unsignedlongvm_start;/* Our start address within vm_mm. */
unsignedlongvm_end;/* The first byte after our end address
within vm_mm. */
/* linked list of VM areas per task, sorted by address */
structvm_area_struct *vm_next;
pgprot_t vm_page_prot;/* Access permissions of this VMA. */
unsignedlongvm_flags;/* Flags, see mm.h. */
structrb_node vm_rb;
/*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap prio tree, or
* linkage to the list of like vmas hanging off its node, or
* linkage of vma in the address_space->i_mmap_nonlinear list.
*/
union{
struct{
structlist_head list;
void*parent;/* aligns with prio_tree_node parent */
structvm_area_struct *head;
} vm_set;
structraw_prio_tree_node prio_tree_node;
} shared;
/*
* A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
* list, after a COW of one of the file pages. A MAP_SHARED vma
* can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
* or brk vma (with NULL file) can only be in an anon_vma list.
*/
structlist_head anon_vma_node;/* Serialized by anon_vma->lock */
structanon_vma *anon_vma;/* Serialized by page_table_lock */
/* Function pointers to deal with this struct. */
conststructvm_operations_struct *vm_ops;
/* Information about our backing store: */
unsignedlongvm_pgoff;/* Offset (within vm_file) in PAGE_SIZE
units, *not* PAGE_CACHE_SIZE */
structfile * vm_file;/* File we map to (can be NULL). */
void* vm_private_data;/* was vm_pte (shared mem) */
unsignedlongvm_truncate_count;/* truncate_count or restart_addr */
#ifndef CONFIG_MMU
structvm_region *vm_region;/* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
structmempolicy *vm_policy;/* NUMA policy for the VMA */
#endif
};
进程所拥有的线性区从来不重叠,并且内核尽力把新分配的线性区与邻接的现有线性区进行合并。如果两个相邻区的访问权限相匹配,就能把他们合并在一起。