内核版本: 4.1

函数原型

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

这是mmap的函数原型,而系统调用的接口在mm/map.c中的:

unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,unsigned long prot, unsigned long flags,unsigned long fd, unsigned long pgoff);

虚拟内存管理

这里我们先介绍两个关于虚拟内存的数据结构。虚拟内存概念的相关资料网上已经足够的丰富,这里我们从内核的角度来分析。虚拟空间的管理是以进程为基础的,每个进程都有各自的虚存空间,除此之外,每个进程的“内核空间”是为所有的进程所共享的。一个进程的虚拟地址空间主要由两个数据结构来描述: mm_struct 和vm_area_struct。

The Memory Descriptor

mm_struct包括进程中虚拟地址空间的所有信息,mm_struct定义在include/linux/mm_types.h:

struct mm_struct {struct {struct vm_area_struct *mmap;            /* vm_area_struct的链表 */pgd_t * pgd;             /* 指向进程的页目录 *//* ... */int map_count;               /* vm_area_struct数量 *//* ... */unsigned long total_vm;          /* 映射的Page数量 *//* ... */unsigned long start_code, end_code, start_data, end_data;     /* 代码段起始结束位置,数据段起始结束位置 */unsigned long start_brk, brk, start_stack;              /* 堆的起始结束位置, 栈因为其性质,只有起始位置 */unsigned long arg_start, arg_end, env_start, env_end;    /* 参数段,环境段的起始结束位置 *//* ... */}}

结合mm_struct和下图32位系统典型的虚拟地址空间分布更能直观的理解(来自《深入理解计算机系统》):

Virtual Memory Area

vm_area_struct描述了虚拟地址空间的一个区间, 一个进程的虚拟空间中可能有多个虚拟区间, vm_area_struct同样定义在include/linux/mm_types.h:

/** 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;         /* 在虚拟地址空间的起始位置 */unsigned long vm_end;           /* 在虚拟地址空间的结束位置*//* 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. *//* Function pointers to deal with this struct. */const struct vm_operations_struct *vm_ops; /* 对这个区间进行操作的函数 */struct mm_struct *vm_mm;        /* vma所属的虚拟地址空间 */pgprot_t vm_page_prot;          /* Access permissions of this VMA. */unsigned long vm_flags;         /* Flags, see mm.h. */struct file * vm_file;          /* 映射的文件,匿名映射即为nullptr*/
}

下图是某个进程的虚拟内存简化布局以及相应的几个数据结构之间的关系:

mmap是什么?

相信做过Linux开发的兄弟都或多或少用过,或者听说过mmap,但可能并不完全了解mmap的作用。

mmap字面上是内存映射的意思,听起来比较抽象,其用法有很多,但总结起来,主要是如下两个用途:

  1. 将文件内容映射到进程用户态的虚拟地址空间中,如此,进程就可以通过读写相应的虚拟地址空间内容,而直接读写相应文件中的内容。如此映射最大的好处是,进程可以直接从用户态访问文件中的数据,而不需要用户态和内核态之间的内存拷贝操作(正常流程下,如果想要向文件中写数据,需要将数据从用户态拷贝到内核态,然后再从内核态写入文件),相当于少了一次内存拷贝操作,这也是人们常说的零拷贝技术之一。当然,这里的文件不限于普通文件,Unix环境中,一切皆文件嘛,这里的文件完全可能是特殊文件,比如设备文件,那相应的mmap操作就需要单独的驱动实现了。
  2. 分配内存。当mmap中传入的fd为空时,其作用就是分配内存,类似于malloc(其实malloc的glibc实现中就使用了mmap来分配内存),俗称“匿名映射”,匿名的意思就是fd为空,名字很抽象,本质不复杂:就是在进程的虚拟地址空间中分配一段虚拟内存(用vma表示),物理内存在缺页异常中分配,并修改相应页表。

mmap基本原理

如前面所述,mmap主要有两种用途,其中第一种用途分两种情况(普通文件和特殊文件),这里分别描述相关原理:

1.普通文件的mmap基本原理为:每个文件(file)都定义了相应的文件操作数据结构(file_operations),该结构中定义了mmap操作,比如ext3文件系统文件对应的文件操作为:ext3_file_operations,对应的mmap操作接口为:generic_file_mmapgeneric_file_mmap中就是创建(或查找利用现有的)vma,然后设置相应的成员,包括缺页异常对应的处理钩子,最后返回相应的虚拟地址。当进程访问写相应的虚拟地址时,硬件会触发缺页异常(磁盘页未缓存到屋里内存中),此时会进入缺页异常流程(do_page_fault),然后会进入之前设置的缺页异常钩子,该钩子会触发文件系统的写入操作,最终会将数据写入到文件中。

2.特殊文件(以设备文件为例)的mmap的基本原理与上述普通文件类似,主要差别在于:其定义的文件操作不同,对应的接口不同;其实现取决于具体的驱动,流程与普通文件实现可以完全不同,这里不详述。

3.匿名映射的基本原理:由于没有具体的fd,没有对应的文件,匿名映射没有对应的文件操作,其流程比较直接,主要还是创建(或查找利用现有的)vma,然后设置相应的成员,返回相应的虚拟地址。当进程访问写相应的虚拟地址时,硬件会触发缺页异常(因为相应的页表项还没有创建),此时会进入缺页异常流程(do_page_fault),然后会进入匿名映射对应的流程,主要就是为虚拟地址范围创建相应的页表,本质上,就是分配了相应的物理内存。

代码流程

mmap流程

mmap有相应的系统调用接口,从系统调用开始的大致流程如下(代码不是很好找,需要仔细看看):

SYSCALL_DEFINE6(mmap_pgoff, ...sys_mmap_pgoff    SYSCALL_DEFINE6(mmap_pgoff, ...vm_mmap_pgoffdo_mmap_pgoffmmap_regionfile->f_op->mmap() //不同文件(驱动)自己定义的mmap钩子,比如ext3文件系          统对应为`generic_file_mmap`

文件缺页异常流程

do_page_fault__do_page_faulthandle_pte_fault__handle_mm_faulthandle_pte_faultdo_faultdo_shared_fault__do_faultvma->vm_ops->fault()  //文件系统或驱动注册的缺页异常钩子,如ext4文件对应为filemap_fault

匿名映射缺页异常流程

do_page_fault__do_page_faulthandle_pte_fault__handle_mm_faulthandle_pte_faultdo_anonymous_pagemk_pte //创建页表项set_pte_at

普通文件映射与匿名文件映射的用法

用法举例1

字符设备文件的驱动代码编写

总结

1.对于普通文件的mmap,在执行后仅仅是分配了一个可用的虚拟地址以及缺页处理函数,访问的时候按照缺页处理将文件从磁盘上读入,修改后的内存页最终会回写到磁盘上

2.以字符设备为例,设备文件的大小为0;设备文件的mmap需要自己定义驱动函数来返回一个映射地址。

最清楚的mmap()详解与源码分析相关推荐

  1. hadoop作业初始化过程详解(源码分析第三篇)

    (一)概述 我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程.在作业到达JobTracker之后初始化之前,JobTracker会通过submit ...

  2. SpringMVC异常处理机制详解[附带源码分析]

    SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...

  3. spark RDD详解及源码分析

    spark RDD详解及源码分析 @(SPARK)[spark] spark RDD详解及源码分析 一基础 一什么是RDD 二RDD的适用范围 三一些特性 四RDD的创建 1由一个已经存在的scala ...

  4. spark 调度模块详解及源码分析

    spark 调度模块详解及源码分析 @(SPARK)[spark] spark 调度模块详解及源码分析 一概述 一三个主要的类 1class DAGScheduler 2trait TaskSched ...

  5. FPGA学习之路—接口(2)—I2C协议详解+Verilog源码分析

    FPGA学习之路--I2C协议详解+Verilog源码分析 定义 I2C Bus(Inter-Integrated Circuit Bus) 最早是由Philips半导体(现被NXP收购)开发的两线时 ...

  6. HashMap、ConcurretnHashMap面试题详解,源码分析

    文章目录 面试题 HashMap.LinkedHashMap和TreeMap的区别是什么? ①:为什么hashmap每次扩容大小为2的n次方? ③:jdk1.7的hashmap的扩容操作是在元素插入之 ...

  7. Epoll详解及源码分析

    文章来源:http://blog.csdn.net/chen19870707/article/details/42525887 Author:Echo Chen(陈斌) Email:chenb1987 ...

  8. 安卓PopupWindow使用详解与源码分析(附项目实例)

    基本用法 首先定义弹窗的Layout文件 res/layout/popup_window.xml <?xml version="1.0" encoding="utf ...

  9. JDK动态代理实现原理详解(源码分析)

    无论是静态代理,还是Cglib动态代理,都比较容易理解,本文就通过进入源码的方式来看看JDK动态代理的实现原理进行分析 要了解动态代理的可以参考另一篇文章,有详细介绍,这里仅仅对JDK动态代理做源码分 ...

最新文章

  1. 如何打开写好的jpetstore
  2. python安装准备_Python安装准备
  3. Java对象、List集合、Map和JSON格式数据的互转(谷歌的gson-2.2.4.jar包)
  4. python怎么安装tensorflow-Python使用pip安装TensorFlow模块
  5. 如何使用SAP Cloud for Customer的Key User Tool将Mashup添加到UI上
  6. Netty工作笔记0075---handler链调用机制实例1
  7. 这样就算会了PHP么?-7
  8. MySQL 开发实践
  9. Kafka+Spark Streaming+Redis实时系统实践
  10. c语言程序设计自学网进阶,谭浩强老师C语言教程程序设计
  11. 【干货】大学本科生零基础如何开始做发明类竞赛项目
  12. 8647服务器装系统,今天重新安装了系统,麻烦请红夜鬼先生进来帮我看一下
  13. 案例二——网页倒计时(秒杀)
  14. 计算机专业文书范文,美国留学文书技巧-美国计算机专业博士的申请个人陈述范文...
  15. 多人协作共享画板——多人画板的bug及分析
  16. CSS如何修改滚动条的样式?
  17. 一种简单的贝塞尔插值算法
  18. ERD Online 4.0.4 元数据在线建模(免费、私有部署)
  19. [Python] 错误“IndentationError: unindent does not match any outer indentation level”是什么意思?...
  20. ArcGIS Pro 中的编辑器

热门文章

  1. centOS上docker 的简单使用
  2. Guava区间-Range
  3. 模拟实现智能指针auto_ptr,scoped_ptr,shared_ptr
  4. 用python+tornado+mongodb写的一个博客系统
  5. 全部编程皆为Web编程
  6. Yii中Action详解
  7. Revit二次开发之“遍历材质判断材质类别的新方法”BuiltInParameter.PHY_MATERIAL_PARAM_CLASS...
  8. golang 获取路径 文件名 后缀
  9. java json开发包 fastjson 简介
  10. python3 多线程简介