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


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

文章插图
VM_SHARD 用于指定这块虚拟内存区域映射的物理内存是否可以在多进程之间共享 , 以便完成进程间通讯 。
设置这个值即为 mmap 的共享映射 , 不设置的话则为私有映射 。这个等后面我们讲到 mmap 的相关实现时还会再次提起 。
VM_IO 的设置表示这块虚拟内存区域可以映射至设备 IO 空间中 。通常在设备驱动程序执行 mmap 进行 IO 空间映射时才会被设置 。
VM_RESERVED 的设置表示在内存紧张的时候 , 这块虚拟内存区域非常重要 , 不能被换出到磁盘中 。
VM_SEQ_READ 的设置用来暗示内核 , 应用程序对这块虚拟内存区域的读取是会采用顺序读的方式进行 , 内核会根据实际情况决定预读后续的内存页数 , 以便加快下次顺序访问速度 。
VM_RAND_READ 的设置会暗示内核 , 应用程序会对这块虚拟内存区域进行随机读取 , 内核则会根据实际情况减少预读的内存页数甚至停止预读 。
我们可以通过 posix_fadvise , madvise 系统调用来暗示内核是否对相关内存区域进行顺序读取或者随机读取 。相关的详细内容 , 大家可以看下笔者上篇文章 《从 Linux 内核角度探秘 JDK NIO 文件读写本质》中的第 9 小节文件页预读部分 。
通过这一系列的介绍 , 我们可以看到 vm_flags 就是定义整个虚拟内存区域的访问权限以及行为规范 , 而内存区域中内存的最小单位为页(4K) , 虚拟内存区域中包含了很多这样的虚拟页 , 对于虚拟内存区域 VMA 设置的访问权限也会全部复制到区域中包含的内存页中 。
5.5 关联内存映射中的映射关系接下来的三个属性 anon_vma , vm_file , vm_pgoff 分别和虚拟内存映射相关 , 虚拟内存区域可以映射到物理内存上 , 也可以映射到文件中 , 映射到物理内存上我们称之为匿名映射 , 映射到文件中我们称之为文件映射 。
那么这个映射关系在内核中该如何表示呢?这就用到了 vm_area_struct 结构体中的上述三个属性 。
一步一图带你深入理解 Linux 虚拟内存管理

文章插图
当我们调用 malloc 申请内存时 , 如果申请的是小块内存(低于 128K)则会使用 do_brk() 系统调用通过调整堆中的 brk 指针大小来增加或者回收堆内存 。
如果申请的是比较大块的内存(超过 128K)时 , 则会调用 mmap 在上图虚拟内存空间中的文件映射与匿名映射区创建出一块 VMA 内存区域(这里是匿名映射) 。这块匿名映射区域就用 struct anon_vma 结构表示 。
当调用 mmap 进行文件映射时 , vm_file 属性就用来关联被映射的文件 。这样一来虚拟内存区域就与映射文件关联了起来 。vm_pgoff 则表示映射进虚拟内存中的文件内容 , 在文件中的偏移 。
当然在匿名映射中 , vm_area_struct 结构中的 vm_file 就为 null , vm_pgoff 也就没有了意义 。
vm_private_data 则用于存储 VMA 中的私有数据 。具体的存储内容和内存映射的类型有关 , 我们暂不展开论述 。
5.6 针对虚拟内存区域的相关操作struct vm_area_struct 结构中还有一个 vm_ops 用来指向针对虚拟内存区域 VMA 的相关操作的函数指针 。
struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area);vm_fault_t (*fault)(struct vm_fault *vmf);vm_fault_t (*page_mkwrite)(struct vm_fault *vmf);..... 省略 .......}

经验总结扩展阅读