本文共 7357 字,大约阅读时间需要 24 分钟。
一个进程的虚拟地址空间主要由两个数据结来描述。一个是最高层次的:mm_struct(定义在mm_types.h中),一个是较高层次的:vm_area_structs。最高层次的mm_struct结构描述了一个进程的整个虚拟地址空间。较高层次的结构vm_area_truct描述了虚拟地址空间的一个区间(简称虚拟区)。每个进程只有一个mm_struct结构,在每个进程的task_struct结构中,有一个指向该进程的结构。可以说,mm_struct结构是对整个用户空间(注意,是用户空间)的描述。
struct task_struct{ // ... struct mm_struct *mm, *active_mm; // ...};struct mm_struct *mm, *active_mm;
mm:进程所拥有的用户空间内存描述符,
active_mm:进程运行时所使用的内存描述符,
注意:
如图,mm_struct后面一层是不是很熟悉?没错,栈区、内存映射区、堆区、BBS区、数据区、文本区(后续继续讨论)
上图中我们需要注意的是:对于物理内存当中的内核kernel,是只存在一份,所有的进程是用来共享的,内核当中会利用PCB(进程控制块)来管理不同的进程。
以下总结摘自:http://blog.csdn.net/qq_26768741/article/details/54375524
在地址空间中,mmap为地址空间的内存区域(用vm_area_struct结构来表示)链表,mm_rb用红黑树来存储,链表表示起来更加方便,红黑树表示起来更加方便查找。
区别是,当虚拟区较少的时候,这个时候采用单链表,由mmap指向这个链表,当虚拟区多时此时采用红黑树的结构,由mm_rb指向这棵红黑树。这样就可以在大量数据的时候效率更高。
所有的mm_struct结构体通过自身的mmlist域链接在一个双向链表上,该链表的首元素是init_mm内存描述符,代表init进程的地址空间。
atomic_t mm_users;
atomic_t mm_count;
struct mm_struct { struct vm_area_struct * mmap; /* list of VMAs,指向线性区对象的链表头部 */ struct rb_root mm_rb; /* 指向线性区对象的红黑树*/ struct vm_area_struct * mmap_cache; /* last find_vma result 指向最近找到的虚拟区间 */#ifdef CONFIG_MMU /*用来在进程地址空间中搜索有效的进程地址空间的函数*/ unsigned long (*get_unmapped_area) (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags);/*释放线性区的调用方法*/ void (*unmap_area) (struct mm_struct *mm, unsigned long addr);#endif unsigned long mmap_base; /* base of mmap area ,内存映射区的基地址*/ unsigned long task_size; /* size of task vm space */ unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */ pgd_t * pgd; /* 页表目录指针*/ atomic_t mm_users; /* How many users with user space?,共享进程的个数 */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1),主使用计数器,采用引用计数,描述有多少指针指向当前的mm_struct */ int map_count; /* number of VMAs ,线性区个数*/ struct rw_semaphore mmap_sem; spinlock_t page_table_lock; /* Protects page tables and some counters,保护页表和引用计数的锁 (使用的自旋锁)*/ struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung * together off init_mm.mmlist, and are protected * by mmlist_lock */ unsigned long hiwater_rss; /* High-watermark of RSS usage,进程拥有的最大页表数目 */ unsigned long hiwater_vm; /* High-water virtual memory usage ,进程线性区的最大页表数目*/ unsigned long total_vm, locked_vm, shared_vm, exec_vm; unsigned long stack_vm, reserved_vm, def_flags, nr_ptes; unsigned long start_code, end_code, start_data, end_data; /*维护代码区和数据区的字段*/ unsigned long start_brk, brk, start_stack; /*维护堆区和栈区的字段*/ unsigned long arg_start, arg_end, env_start, env_end; /*命令行参数的起始地址和尾地址,环境变量的起始地址和尾地址*/ unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ /* * Special counters, in some configurations protected by the * page_table_lock, in other configurations by being atomic. */ struct mm_rss_stat rss_stat; struct linux_binfmt *binfmt; cpumask_t cpu_vm_mask; /* Architecture-specific MM context */ mm_context_t context; /* Swap token stuff */ /* * Last value of global fault stamp as seen by this process. * In other words, this value gives an indication of how long * it has been since this task got the token. * Look at mm/thrash.c */ unsigned int faultstamp; unsigned int token_priority; unsigned int last_interval; unsigned long flags; /* Must use atomic bitops to access the bits */ struct core_state *core_state; /* coredumping support */#ifdef CONFIG_AIO spinlock_t ioctx_lock; struct hlist_head ioctx_list;#endif#ifdef CONFIG_MM_OWNER /* * "owner" points to a task that is regarded as the canonical * user/owner of this mm. All of the following must be true in * order for it to be changed: * * current == mm->owner * current->mm != mm * new_owner->mm == mm * new_owner->alloc_lock is held */ struct task_struct *owner;#endif#ifdef CONFIG_PROC_FS /* store ref to file /proc//exe symlink points to */ struct file *exe_file; unsigned long num_exe_file_vmas;#endif#ifdef CONFIG_MMU_NOTIFIER struct mmu_notifier_mm *mmu_notifier_mm;#endif};
以下摘自http://blog.csdn.net/qq_26768741/article/details/54375524
linux kernel 使用内存管理的时候,采取的是页式的管理方式,应用程序给出的内存地址是虚拟地址,是经过若干层的页表的转换才能得到真正的物理地址,所以相对来说,进程的
地址空间是一份虚拟的地址空间,每一个地址通过页表的转换映射到所谓的物理地址空间上。在这里所共享的1G的kernel在内存地址是只存一份的,但是对于每一个进程其他的3G的空间,
是存储其他不同的东西,另外,页表具有权限限定,这样也就提供给了每块内存区域,比如我定义了:
char * p="12342";
这里的“12342”是一个常量字符串,它被存放在只读常量存储区,所以这个区域的页表的属性就是只读,这样就可以高效的维护整个进程的地址空间。
每一个进程都会有一个进程描述符,task_struct,task_strust当中的mm指针指向每个进程的内存描述符,而对于每个mm,有都会有单独的页表,
pgt区间是用来维护页表的目录,每一个进程的都有自己的页表目录,需要注意进程的页目录和内核的页目录是不一样的,当程序调度器调度程序运行的时候,这个时候这个地址就会转换成为
物理地址,linux一般采用三级页表进行转换。
/* * 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). */struct vm_area_struct { struct mm_struct * vm_mm; /* The address space we belong to. */ 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 */ struct vm_area_struct *vm_next; pgprot_t vm_page_prot; /* Access permissions of this VMA. */ unsigned long vm_flags; /* Flags, see mm.h. */ struct rb_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 { struct list_head list; void *parent; /* aligns with prio_tree_node parent */ struct vm_area_struct *head; } vm_set; struct raw_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. */ struct list_head anon_vma_chain; /* Serialized by mmap_sem & * page_table_lock */ struct anon_vma *anon_vma; /* Serialized by page_table_lock */ /* Function pointers to deal with this struct. */ const struct vm_operations_struct *vm_ops; /* Information about our backing store: */ unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ struct file * vm_file; /* File we map to (can be NULL). */ void * vm_private_data; /* was vm_pte (shared mem) */ unsigned long vm_truncate_count;/* truncate_count or restart_addr */#ifndef CONFIG_MMU struct vm_region *vm_region; /* NOMMU mapping region */#endif#ifdef CONFIG_NUMA struct mempolicy *vm_policy; /* NUMA policy for the VMA */#endif};