一步一图带你深入理解 Linux 虚拟内存管理( 九 )


现在关于内核如何对进程虚拟内存空间进行布局的内容我们已经清楚了,那么布局之后划分出的这些虚拟内存区域在内核中又是如何被管理的呢?我们接着往下看~~~
5.3 内核如何管理虚拟内存区域在上小节的介绍中,我们知道内核是通过一个 mm_struct 结构的内存描述符来表示进程的虚拟内存空间的,并通过 task_size 域来划分用户态虚拟内存空间和内核态虚拟内存空间 。

一步一图带你深入理解 Linux 虚拟内存管理

文章插图
而在划分出的这些虚拟内存空间中如上图所示,里边又包含了许多特定的虚拟内存区域,比如:代码段,数据段,堆,内存映射区 , 栈 。那么这些虚拟内存区域在内核中又是如何表示的呢?
本小节中 , 笔者将为大家介绍一个新的结构体 vm_area_struct , 正是这个结构体描述了这些虚拟内存区域 VMA(virtual memory area) 。
struct vm_area_struct { unsigned long vm_start;/* Our start address within vm_mm. */ unsigned long vm_end;/* The first byte after our end addresswithin vm_mm. */ /** Access permissions of this VMA.*/ pgprot_t vm_page_prot; unsigned long vm_flags;struct anon_vma *anon_vma; /* Serialized by page_table_lock */struct file * vm_file;/* File we map to (can be NULL). */ unsigned long vm_pgoff;/* Offset (within vm_file) in PAGE_SIZEunits */ void * vm_private_data;/* was vm_pte (shared mem) */ /* Function pointers to deal with this struct. */ const struct vm_operations_struct *vm_ops;}每个 vm_area_struct 结构对应于虚拟内存空间中的唯一虚拟内存区域 VMA,vm_start 指向了这块虚拟内存区域的起始地址(最低地址) , vm_start 本身包含在这块虚拟内存区域内 。vm_end 指向了这块虚拟内存区域的结束地址(最高地址),而 vm_end 本身包含在这块虚拟内存区域之外,所以 vm_area_struct 结构描述的是 [vm_start,vm_end) 这样一段左闭右开的虚拟内存区域 。
一步一图带你深入理解 Linux 虚拟内存管理

文章插图
5.4 定义虚拟内存区域的访问权限和行为规范vm_page_prot 和 vm_flags 都是用来标记 vm_area_struct 结构表示的这块虚拟内存区域的访问权限和行为规范 。
上边小节中我们也提到,内核会将整块物理内存划分为一页一页大小的区域,以页为单位来管理这些物理内存 , 每页大小默认 4K。而虚拟内存最终也是要和物理内存一一映射起来的,所以在虚拟内存空间中也有虚拟页的概念与之对应,虚拟内存中的虚拟页映射到物理内存中的物理页 。无论是在虚拟内存空间中还是在物理内存中,内核管理内存的最小单位都是页 。
vm_page_prot 偏向于定义底层内存管理架构中页这一级别的访问控制权限,它可以直接应用在底层页表中,它是一个具体的概念 。
页表用于管理虚拟内存到物理内存之间的映射关系 , 这部分内容笔者后续会详细讲解 , 这里大家有个初步的概念就行 。
虚拟内存区域 VMA 由许多的虚拟页 (page) 组成,每个虚拟页需要经过页表的转换才能找到对应的物理页面 。页表中关于内存页的访问权限就是由 vm_page_prot 决定的 。
vm_flags 则偏向于定于整个虚拟内存区域的访问权限以及行为规范 。描述的是虚拟内存区域中的整体信息,而不是虚拟内存区域中具体的某个独立页面 。它是一个抽象的概念 。可以通过 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags) 实现到具体页面访问权限 vm_page_prot 的转换 。
下面笔者列举一些常用到的 vm_flags 方便大家有一个直观的感受:
vm_flags访问权限VM_READ可读VM_WRITE可写VM_EXEC可执行VM_SHARD可多进程之间共享VM_IO可映射至设备 IO 空间VM_RESERVED内存区域不可被换出VM_SEQ_READ内存区域可能被顺序访问VM_RAND_READ内存区域可能被随机访问VM_READ , VM_WRITE,VM_EXEC 定义了虚拟内存区域是否可以被读?。?写入,执行等权限 。
比如代码段这块内存区域的权限是可读,可执行 , 但是不可写 。数据段具有可读可写的权限但是不可执行 。堆则具有可读可写 , 可执行的权限(Java 中的字节码存储在堆中,所以需要可执行权限),栈一般是可读可写的权限,一般很少有可执行权限 。而文件映射与匿名映射区存放了共享链接库,所以也需要可执行的权限 。
一步一图带你深入理解 Linux 虚拟内存管理

文章插图
VM_SHARD 用于指定这块虚拟内存区域映射的物理内存是否可以在多进程之间共享,以便完成进程间通讯 。

推荐阅读