进程地址空间:系统中每个用户空间进程所看到的内存。
1 地址空间
进程地址空间由进程可寻址的虚拟内存组成。特点:
1)平坦的:地址空间范围是一个独立的连续区间
2)寻址范围:4GB虚拟内存(32位地址空间中),可以被合法访问的地址空间称为内存区域。如果一个进程访问了不在有效范围中的内存区域,或以不正确的方式访问了有效地址,那么内核就会终止该进程,并返回“段错误”信息。
3)内存区域可包含的对象:
- 可执行文件代码的内存映射称为代码段。(text section)
- 可执行文件的已初始化全局变量的内存映射,称为数据段。(data section)
- 包含未初始化全局变量,也就是bss段的零页的内存映射。
- 用于进程用户空间栈的零页的内存映射
- 每一个诸如C库或动态连接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间
- 任何内存映射文件
- 任何共享内存段
- 任何匿名的内存映射,比如由malloc()分配的内存
2 内存描述符
内存描述符由mm_struct结构体表示,定义在文件<linux/sched.h>中。
操作
#define allocate_mm() (kmem_cache_alloc(mm_cachep, GFP_KERNEL))
#define free_mm(mm) (kmem_cache_free(mm_cachep, (mm)))
3 内存区域
内存区域在linux中也被称为虚拟内存区域(VMA),由vm_area_struct描述,描述了进程地址空间上一段连续的内存范围,定义在linux/mm_types.h中。
操作函数由vm_operations_struct结构体表示。
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf);
int (*access)(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write);
#ifdef CONFIG_NUMA
int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
unsigned long addr);
int (*migrate)(struct vm_area_struct *vma, const nodemask_t *from,
const nodemask_t *to, unsigned long flags);
#endif
};
实际使用中的内存区域可以使用/proc文件系统和pmap工具,查看给定进程的内存空间和其中所含的内存区域。
cat /proc/<pid>/maps
pmap <pid>
4 操作内存区域
内存区域
//在<mm/mmap.c>中
//在指定的地址空间中搜索第一个vm_end大于addr的内存区域
struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
struct vm_area_struct **pprev);
static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
地址区间
//创建一个新的线性地址空间
static inline unsigned long do_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long offset)
//从特定的进程地址空间中删除指定地址区间
int do_munmap(struct mm_struct *, unsigned long, size_t);