写点什么

浅谈 mmap

  • 2019 年 11 月 14 日
  • 本文字数:2236 字

    阅读完需:约 7 分钟

浅谈mmap

作者说:最近在工作中遇到一个 mmap 使用相关的问题,造成了一定的困惑,于是花了些时间补了下 mmap 的功课,在这里分享给大家,错误和不足之处大家多指教。


相关背景知识

  • 说到 mmap 的使用,我们首先要了解一下进程的虚拟进程地址空间的概念。Linux 上为了作进程隔离,每个进程都运行在自己的单独的虚拟进程空间,同时物理机上内存有限,每个进程使用虚拟内存地址来隔离又共享物理内存。我们平时在代码里获取的地址就是虚拟地址;

  • 放一张进程虚拟地址空间草图,网上也可以很容易找到更精美的



1.我们在程序中申请内存的操作,实际上只是在进程地址空间相应部分申请了一段虚拟地址,当实际对这段虚拟地址进行读写操作时,才会分配真正的物理内存;


2.通常 x86 Linux 采用段页式的内存管理模式,这块不具体展开,简单来说就是 CPU 访问的逻辑地址,然后经过分段机制转换成线性地址(你可以简单理解成等价于上面说的虚拟地址),再经过分页机制转换成物理地址,第一次访问的时候由于实现物理地址还没有分配,会产生缺页中断来分配物理地址,用它来填充对应的页表项;


3.通过 read 系统调用来读取磁盘上的文件时,文件内容会先被读到内存的 page inode 部分,然后再从 page cache 中拷贝到应用层的读缓存 buffer 中;对于打开的文件,内核都会在内存中维护一个 inode 结构体(对于同一个文件,即使被 open 多次,内核也仅维护这一个 inode),其有一个成员是 struct address_space *i_mapping , 它用来维护这个文件被读取的所有部分在内存中的缓存,其使用 xarray(全新封装了基数树的操作)来存储这个物理页(struct page), 如下图:




mmap 简介

  • 先看原型:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)

  • 功能:


1.分配一块新的连续的进程虚拟地址段(对应内核中的结构体就是 vm_area_struct)并返回其起始地址,如果给定了第一个参数,就优先从这个地址开始分配进程虚拟地址;


2.如果提供了 fd 文件句枘,则映射文件内容到进程虚拟地址;


3.mmap 的参数较多,其中 prot 和 flags 的可选项也比较多,具体大家可以使用 man 命令查看;


mmap 的几种典型应用

  • 不同进程(可以是非父子进程)间共享映射


1.这种情况需要借助磁盘文件,实际上是共享这个磁盘文件,将这个磁盘文件映射到各自的进程虚拟地址空间,但是其虚拟地址空间分页转换后其页表项对应的物理内存是相同的;


2.典型用法是需提供一个打开的文件句柄,使用 MAP_SHARED flag


int fd = open ("[filepath]", O_RDWR))


void *addr = mmap (NULL, [mmaping length], PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)


  • 非子进程间通讯


1.父进程使用 fork 创建子进程,父子进程间可以使用 mmap 来通读;


2.典型用法是无需提供打开的文件句柄, 使用 MAP_SHARED | MAP_ANONYMOUS flag,


void *addr = mmap (NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
复制代码


  • 进程通过 mmap 来读写文件


1.从上面 相关背景知识 一节可知使用 read 系统调用读文件时,数据需经过 磁盘拷贝到 page cache, page cache 再拷贝到应用层缓存 bufffer, 这两个数据拷贝;


2.使用 mmap 时,磁盘数据也是先读到 page cache 中,然后会将 mmap 返回的虚拟地址最终对应的页项表内容设定为和前面的 page chache 相同的物理页, 这样一来就免去了第二次的数据拷贝;


3.用个示意图来说明一下:




  • 用作 glibc 中 malloc 申请内存


1.通常我们都说是通过调用 malloc 来申请堆上内存,但实际上其内部实现使用了 brk 和 mmap 两种系统调用,当申请的内存大于 128K 时,使用 mmap


2.典型用法是无需提供打开的文件句柄, 使用 MAP_PRIVATE | MAP_ANONYMOUS flag


void *addr = mmap (NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
复制代码


  • mmap 的写时拷贝


1.如果我们在调用 mmap 时提供一个打开的文件句两,但使用 MAP_PRIVATE 的 flags, 那这时对其的写操作并不能真正修改对应的磁盘文件,它会作写时拷贝,退化成匿名映射


## mmap 作磁盘文件映射时的特别说明

1.mmap 映射的虚拟地址长度(即 mmap 的第二个参数)需要对齐到物理页大小,在 32 位系统上通常是 4K, 这一特点会导致一些有趣的事情发生,我们来看一下:假如一个文件的大小是 5000Byte, 刚好比 4K 大一些,我们用 mmap 来从文件开始的位置来映射它,mmap 的第二个参数给 5000, 因为需要页面对齐,实现映射的虚拟地址长度将是两个 4k,即 8192, 8192 - 5000 = 3192 的部分用 0 填充,也是可以被访问到;


2.如果用 mmap 映射某个文件时,这个文件大小为 0, 不会分配任何的物理内存,也不能作任何的读写访问;当向文件中写入数据后,通过 mmap 返回的虚拟地址可以访问这部分文件内容;


mmap 与内存换入换出

1.由前面的介绍我们知道 mmap 不管是映射磁盘文件,还是作匿名映射,最终都会分配物理内存页,因此这个物理内存页在内存紧张时就有备换出的可能,当然 mmap 提供了 MAP_LOCKED,可以锁定内存不被换出,我们不考虑这种情况;


2.如果使用 mmap 映射的是磁盘文件,其存在物理页的内容会被清空,pte 将记录这种情况,再次需要访问时,会重新读取磁盘文件,缓存在 page cache 中;


3.如果使用 mmap 作匿名映射,没有相关联的磁盘文件(或者使用 MAP_PRIVATE 方式映射磁盘文件),发生内存换出时,将被交换到 swap 中,swap 实际上也对应着磁盘块,最终也是写在磁盘上;


本文转载自公众号 360 云计算(ID:hulktalk)。


原文链接:


https://mp.weixin.qq.com/s/h4LwSRAsDgRqOq3mLt_SCw


2019 年 11 月 14 日 14:071156

评论

发布
暂无评论
发现更多内容

Java 里面的异常,java语言程序设计教程pdf

Java 程序员 后端

java-集合-Map(双列)——迪迦重制版(1),关于线程池的五种实现方式

Java 程序员 后端

Java反射(1),java架构师薪资

Java 程序员 后端

java反射map转实体类 实体转map,微服务架构的优缺点

Java 程序员 后端

java8实战读书笔记:初识Stream、流的基本操作,nginx架构原理

Java 程序员 后端

Java反射,mysql开发教程

Java 程序员 后端

Java 高并发之设计模式,深入linux内核架构mobi

Java 程序员 后端

Java-进阶:集合框架1,java三个技术平台

Java 程序员 后端

java8实战读书笔记:Lambda表达式语法与函数式编程接口

Java 程序员 后端

Java发送邮件,字节跳动上千道精选面试题还不刷起来

Java 程序员 后端

Java在2018年的形势,MySQL优化原理分析及优化方案总结

Java 程序员 后端

Java-Parallel GC介绍,springmvc面试题高级

Java 程序员 后端

java-集合-Map(双列)——迪迦重制版,zookeeper面试

Java 程序员 后端

JavaFx:窗口切换和ListView以及TableView的值绑定,docker面试题

Java 程序员 后端

JavaWeb Ajax详解,linux操作系统基础教程安俊秀课后答案

Java 程序员 后端

Java中的程序控制流程,java面试常问知识

Java 程序员 后端

JavaWeb学习笔记6——事务实例,我的支付宝3面+美团4面+拼多多四面

Java 程序员 后端

Java中使用Spring-security(一),java做视频直播

Java 程序员 后端

Java中的几种阻塞队列(1),mybatis返回主键原理

Java 程序员 后端

Java中高级核心知识全面解析——Dubbo,kafka入门到精通文档

Java 程序员 后端

Java使用JDBC开发 之 DBCP连接池,保洁阿姨看完都会了

Java 程序员 后端

java响应重定向发送post请求,spring+mybatis基础知识

Java 程序员 后端

Java 虚拟机1:什么是 Java,太完整了

Java 程序员 后端

Java-进阶:集合框架1(1),java分布式系统面试题

Java 程序员 后端

JavaWeb之Servlet技术(二),java基础程序设计题

Java 程序员 后端

Java中的Type类型详解,javase菜鸟教程

Java 程序员 后端

Java中高级核心知识全面解析——消息队列(1),看完这一篇就够了

Java 程序员 后端

Java中的几种阻塞队列,kalilinux渗透教程

Java 程序员 后端

Java中的初始化与清理,kafka参数调优

Java 程序员 后端

Java中的容器,Java开发进大厂面试必备技能

Java 程序员 后端

Java中高级核心知识全面解析——消息队列,mybatis映射原理

Java 程序员 后端

浅谈mmap_文化 & 方法_刘伟_InfoQ精选文章