1.进程地址空间
- 进程地址空间(Process Address Space) 指进程可以寻址的虚拟地址空间
- 进程没有权限寻址内核空间的虚拟地址,只能通过系统调用间接访问
- 用户空间的进程地址空间称为内存区域(memory area)。进程可以通过内核的内存管理机制动态地添加和删除这些内存区域,采用VMA数据结构来描述
- 内存区域包含如下内容:
a).代码段映射
b).数据段映射
c).用户进程的栈:用户空间的最高地址
d)MMAP映射区域:mmap系统调用,如映射一个文件的内容到进程地址空间
e).堆映射区域:malloc()函数分配的进程虚拟地址就是这段区域 - 每个内存区域不能相互重叠
2.内存描述符mm_struct
struct mm_struct {
struct vm_area_struct * mmap; //指向虚拟区间(VMA)的链表,即链表头
struct rb_root mm_rb; //指向线性区对象红黑树的根,VMA红黑树的根节点
unsigned long(*get_unmapped_area) (struct file *filp,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);//判断内存空间是否有足够的空间,返回一段没有映射的空间的其实地址
unsigned long mmap_base; /* base of mmap area */
pgd_t * pgd; //指向进程的页表PGD目录
atomic_t mm_users; //次使用计数器,使用这块空间的个数
atomic_t mm_count; //主使用计数器
spinlock_t page_table_lock; //线性区的自旋锁和页表的自旋锁
struct list_head mmlist; //init的地址空间
unsigned long total_vm, locked_vm, shared_vm, exec_vm;
//total_vm 进程地址空间的大小(页数)
//locked_vm 锁住而不能换出的页的个数
//shared_vm 共享文件内存映射中的页数
unsigned long start_code, end_code, start_data, end_data;
//start_code 可执行代码的起始地址
//end_code 可执行代码的最后地址
//start_data已初始化数据的起始地址
// end_data已初始化数据的最后地址
unsigned long start_brk, brk, start_stack;
//start_stack堆的起始位置
//brk堆的当前的最后地址
//用户堆栈的起始地址
...
};
3.VMA管理
struct vm_area_struct {
/* The first cache line has the info for VMA tree walking. */
unsigned long vm_start; /* VMA在进程地址空间的起始地址 */
unsigned long vm_end; /* VMA在进程地址空间的结束地址 */
/* linked list of VM areas per task, sorted by address */
struct vm_area_struct *vm_next, *vm_prev; /* 进程的VMA链接成一个链表 */
struct rb_node vm_rb; /* VMA作为一个节点加入红黑树中 */
/*
* Largest free memory gap in bytes to the left of this VMA.
* Either between this VMA and vma->vm_prev, or between one of the
* VMAs below us in the VMA rbtree and its ->vm_prev. This helps
* get_unmapped_area find a free area of the right size.
*/
/* Second cache line starts here. */
struct mm_struct *vm_mm; /* 指向该VMA所属的进程struct mm_struct. */
pgprot_t vm_page_prot; /* Access permissions of this VMA. */
unsigned long vm_flags; /* Flags, see mm.h. */
/*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap interval tree.
*/
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} 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 */
/* 用于管理RMAP方向映射 */
/* 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 */
struct file * vm_file; /* File we map to (can be NULL). */
...
} __randomize_layout;
4. malloc分配函数
- malloc函数会使用系统调用brk去申请内存
SYSCALL DEFINE1(brk,unsigned long, brk)
- malloc为用户空间分配进程地址空间,用内核术语就是分配一块VMA
-
- 每个用户进程有自己的一份页表,mm_struct数据结构中有一个pgd成员指向这个页表的基地址
5. mmap
- mmap是用户态常用的用于建立文件映射或匿名映射的函数,主要分为四种类型
- 私有匿名映射,通常用于分配内存
- 共享匿名映射,通常用于进程间共享内存
- 私有文件映射,通常用于加载动态库
- 共享文件映射,通常用于内存映射I/O,进程间通信