当前位置: 首页 > java >正文

【linux3.10】从mmap的实现来看vma的组织和使用

准备

概念明晰

  1. mmap:为什么会有mmap?我们知道,当我们在进程中申请内存写内存的时候,实际上是直接写在了这个(虚拟)内存对应的物理内存上。而我们读写文件时,却要在内核经过一次拷贝,那么有没有办法像读写内存那样读写文件,从而省去这次拷贝呢?mmap是linux提供的一个解决方案,用户可以把文件映射进内核,内核返回一个地址,用户对这个地址进行操作,就等于直接对文件进行读写,优点是省去了常规读写文件的把用户态数据拷贝进内核的开销,并且多个进程可以映射同一个文件,也是一种多进程通信的方案。关于共享内存,可以参阅宋宝华:世上最好的共享内存(Linux共享内存最透彻的一篇)
  2. vma:全称virtual_memory_area,直译过来就是虚拟内存区域。我们知道,linux是用虚拟内存管理进程的,进程申请内存时内核并不会直接分配物理内存给我们(万一用户分配了内存却不用不就很亏),而是在内核留下一条记录,等到真正要读写这段内存的时候才会给我们分配物理内存。虚拟内存有几个好处,1.隔离进程环境,是多进程运行的基础。2. 给每个进程提供更大的逻辑内存。mmap当然也使用到了虚拟内存,调用mmap的时候会返回一个内存地址,这个地址也是虚拟内存的地址,此时并没有分配物理内存,等到实际读写时才分配物理内存。

进程地址空间的布局

进程地址空间的布局有两种结构,一种是经典结构,另一种是改良后的布局结构。

经典布局

图示来自《深入Linux内核架构》
图示来自《深入Linux内核架构》

改良布局

在这里插入图片描述
图示来自《深入Linux内核架构》

  可以看到,mmap区域都是从mm->mmap_base开始,在经典布局下为TASK_UNMAPPED_BASE。mm也就是memory_manage,结构类型为mm_struct,是用于进程管理内存的数据结构,我们这里用到的不多。我们这里只讨论经典布局,也就是MMAP区域由低地址向高地址增长。

进程地址空间全景

在这里插入图片描述
  可以看到,整个进程的地址空间都是由vm_area_struct构成的,堆栈的背后都是一个个匿名页(page),而堆栈的权限又不相同。data segment, text segment 和mmap segment的背后都是一个个的文件页(page),它们的执行权限又不相同。这些匿名页和文件页共同组成了进程的整个地址空间。
图示来自
Process address space

数据结构

虚拟内存结构:

  内核使用struct vm_area_struct结构来表示一段虚拟内存
结构如下:

/** 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 {/* The first cache line has the info for VMA tree walking. */unsigned long vm_start;		/* Our start address within vm_mm. */unsigned long vm_end;		/* The first byte after our end addresswithin vm_mm. *//* linked list of VM areas per task, sorted by address */struct vm_area_struct *vm_next, *vm_prev;struct rb_node vm_rb;/** 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.*/unsigned long rb_subtree_gap;/* Second cache line starts here. */struct mm_struct *vm_mm;	/* The address space we belong to. */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, or* linkage of vma in the address_space->i_mmap_nonlinear list.*/union {struct {struct rb_node rb;unsigned long rb_subtree_last;} linear;struct list_head nonlinear;} 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_SIZEunits, *not* PAGE_CACHE_SIZE */struct file * vm_file;		/* File we map to (can be NULL). */void * vm_private_data;		/* was vm_pte (shared mem) */#ifndef CONFIG_MMUstruct vm_region *vm_region;	/* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMAstruct mempolicy *vm_policy;	/* NUMA policy for the VMA */
#endif
};
  1. vm_start和vm_end:虚拟内存的开始和结束地址
  2. vm_next, vm_prev:该任务(进程/线程)所有的vma结构会组成一个有序链表,按地址从低到高排序。vm_next和vm_prev就是链表的前一个和后一个元素。
  3. vm_rb:该任务(进程/线程)的所有vma结构会组成一颗红黑树,按地址从低到高排序。vm_rb就是它所在的节点。
  4. rb_subtree_gap:mmap使用augmented_tree和rb_subtree_gap来提升查找地址的性能。翻看linux源码可知,3.8之前查找地址的过程为线性的,时间复杂度为O(n),对应的函数是arch_get_unmapped_area。在3.8使用augmented_tree和rb_subtree_gap优化了该过程,查找地址的时间复杂度为O(logn),对应的函数是unmapped_area。可以说是一个巨大的性能提升了,我们下面会详述这个变量的使用。
  5. vm_mm:此虚拟内存区域所在的内存管理实例。每个vma会通过这个指针反向指向对应mm(memory_manage)实例。
  6. vm_page_prot:_PAGE_READ、_PAGE_WRITE和_PAGE_EXECUTE等,表示此区域的访问权限
  7. vm_flags:VM_READ、VM_WRITE、VM_EXEC、VM_SHARED分别指定了页的内容是否可以读、写、执行,或者由几个进程共享。 VM_MAYREAD、VM_MAYWRITE、VM_MAYEXEC、VM_MAYSHARE用于确定是否可以设置对应的VM_* 标志。这是mprotect系统调用所需要的。VM_GROWSDOWN和VM_GROWSUP表示一个区域是否可以向下或向上扩展(到更低或更高的虚拟地址)。由于堆自下而上增长,其区域需要设置VM_GROWSUP。VM_GROWSDOWN对栈设置,该区域自顶向下增长。
  8. shared:下面这个让人望而生畏的union结构,是为了实现文件页的反向映射。
  9. anon_vma_chain和anon_vma:为了实现匿名页的反向映射。反向映射这里涉及内容很多,会单独写一篇文章介绍,这里暂时跳过。
  10. vm_ops:是一个指向许多方法集合的指针。用于在虚拟内存区域上执行一些操作。
struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void <
http://www.xdnf.cn/news/11333.html

相关文章:

  • 解决mfc100u.dll丢失
  • ffmpeg和H264视频的编解码
  • 灰度、灰度级、分辨率、像素值;
  • 详细说明如何实现简易轮播效果
  • 电脑技巧:进程管理工具Process Explorer介绍
  • 聚水潭ERP集成用友NC(聚水潭主供应链)
  • U盘启动盘怎么制作?
  • 程序员必备的15个接单平台,拥有即将获得“钞能力”!
  • 芯片架构设计及其作用
  • 【C语言】C语言 学生成绩管理系统(源码+报告)【千行代码】【独一无二】
  • CLOSE_WAIT状态的原因与解决方法
  • 一文彻底搞懂进程间通信方式
  • 网关(Gateway)
  • Win10系统搭建个人hMailServer邮件服务结合内网穿透远程发邮件
  • XSD(Xml Schema Definition)详解
  • 文菌装NAS E5:超详细!手把手教您安装黑群晖918+6.2保姆级教程
  • 生态增长 TVL 飙升,Metis 或是 Layer2 最具潜力黑马
  • 编译原理-10-SDT
  • 深度强化学习及其在军事领域中的应用综述
  • 需求管理的主要内容包括哪些
  • 如何配置JDK
  • 2024年最全AutoRuns下载安装使用教程(图文教程)超详细,成功入职阿里
  • 2024年运维最新Linux系统的web管理工具——webmin搭建,2024年最新蚂蚁金服内推四面
  • 深入理解计算机系统(CSAPP)含lab详解 完结
  • 聚类(clustering)与分类(Classification)的区别
  • C语言之scanf/sprintf、fscanf/fprintf、sscanf/sprintf、snprintf
  • Java 7的七大新功能
  • String index out of range: 100 报错详解
  • 虚拟机下载安装及其一些指令(VMware)
  • 守护进程