Linux下mmap_linux mmap-程序员宅基地

技术标签: 运维  linux  服务器  

目录

一.mmap简介

二.为什么需要使用mmap

三.mmap的使用

四.mmap原理


一.mmap简介

什么是mmap了?从名字上来看是memory map也就是地址映射,是一种内存映射文件的方法。mmap是一个可以将一个文件或者其它对象映射到进程的地址空间实现磁盘的地址和进程虚拟地址空间一段虚拟地址的一一对应关系。通过mmap这个系统调用我们可以让进程之间通过映射到同一个普通文件实现共享内存,普通文件被映射到进程地址空间当中之后,进程可以向访问普通内存一样对文件进行一系列操作。

二.为什么需要使用mmap

我们平时再读取文件的时候我们经常使用的方法就是read和write这两个操作系统给我们提供的方法来读写文件的时候,我们需要进行两次拷贝。由于read和write是系统调用所以我们需要先从用户态进入到内核态,然后将磁盘当中的数据拷贝到操作系统的缓冲区当中,然后再将缓冲区当中的数据拷贝到用户态当中。在这个过程当中我们进行了两次拷贝。其过程大致如下图所示:

 

但是如果我们使用mmap就可以减少一次拷贝这样带来性能上的提升是巨大的。并且我们采用内存操作比read和write要简单一些,我们不需要在用户层定义缓冲区用来保存从内核缓冲区读上来的数据,从而节约了内存的消耗。其大致流程如下:

总结:

  • 日常当中使用read或者wirte时需要进行两次拷贝一次是从文件拷贝到内核缓冲区,一次是从内核缓冲区拷贝到用户态。当我们使用mmap时可以减少第二次拷贝,一旦内核将文件映射到内存之后用户进程就可以操作这些数据了,用户进程只需要修改内核当中的内容然后通过内核的内存管理器自动将这些数据刷新到磁盘当中。
  • mmap可以内存提高性能,内核空间和用户空间共用一个缓冲区,如果多个进程正在同一个文件当中进行IO操作那么他们通过使用mmap能够共享一个内核缓冲区从而到达减少内存的消耗

三.mmap的使用

1.首先我们来看看mmap这个函数的声明:

 #include <sys/mman.h>
 void *mmap(void *addr, size_t length, int prot, int flags, 
int fd, off_t offset);

  函数说明:

 创建虚拟内存到物理内存或者文件的映射,下面我们来看看他的这几个参数:

  • addr:映射区的起始地址,如果是NULL系统自动分配
  • length:字节长度自动按照4kb对齐所以建议大小一般填成4kb的整数倍
  • port:映射区域的权限
  • flags:映射的标志位
  • fd:文件描述符
  • offset:文件偏移量自动按照4k对齐

下面我们来说明一下port的取值:

PORT_EXEC:映射的区域具有可执行权限

PROT_READ:映射的区域具有可读权限

PROT_WRITE:映射区域具有可写权限

PROT_NONE:映射区域不可被访问

对应flags的取值:

MAP_SHARED:对映射区域的写入操作直接反映到文件当中

MAP_FIXED:若在start上无法创建映射则失败(如果没有此标记会自动创建)

MAP_PRIVATE:对映射区域的写入操作只反映到缓冲区当中不会写入到真正的文件

MAP_ANONYMOUS:匿名映射将虚拟地址映射到物理内存而不是文件(忽略fd)

MAP_DENYWRITE:拒绝其它文件的写入操作

MAP_LOCKED:锁定映射区域保证其不被置换

返回值:函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

下面我们来演示一下映射到物理内存的案例:

#include <iostream>
#include <sys/mman.h>
#include <cstring>
#include <cerrno>
#include <cstdio>
using namespace std;
static const int SIZE = 4096;
int main()
{
    char *str = (char *)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    //注意MAP_PRIVATE和MAP_SHARED
    //建立映射
    if (str == MAP_FAILED)
    {
        printf("%s\n", strerror(errno));
        return -2;
    }
    strcpy(str, "hello ksy");
    puts(str);
    //用于取消映射
    munmap(str, SIZE);

    return 0;
}

运行结果:

 下面我们来看一下这个映射到文件该如何进行操作了,这个是特别容易错的。

下面直接给代码(注意这个代码是错误的)

#include <iostream>
#include <sys/mman.h>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
using namespace std;
static const int SIZE = 4096;
int main()
{
    int fd=open("./a.txt",O_RDWR|O_CREAT,0644);
    if(fd<0){
        printf("%s\n",strerror(errno));
        return -1;
    }
    char *str = (char *)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    //注意MAP_PRIVATE和MAP_SHARED
    //建立映射
    if (str == MAP_FAILED)
    {
        printf("%s\n", strerror(errno));
        close(fd);
        return -2;
    }
    strcpy(str,"helloworld");
    close(fd);
   

    return 0;
} 

然后我们编译一下然后再看一下结果:

 很多老铁可能直接就懵逼了,没问题啊文件也有啊映射也成功了啊为什么就是映射出现错误了。下面我们来分析一下:

mmap是将虚拟内存映射到文件(物理内存)。按照我们的想法"helloworld"这个字符串应该是要被写入到文件当中。但是我们想一下我们这个文件是新创建的,好像大小是0个字节耶,那么在映射的时候好像也是映射了0个字节,所以这个文件映射过来的内存是没有的,此时我们让里面写东西崩溃了也是正常的。此时我们可以使用truncate函数对文件提前进行处理一下

下面我们来看一下truncate这个函数的原型:

 int truncate(const char *path, off_t length);

函数说明:truncate()会将参数path指定的文件大小改为参数length指定的大小。 如果原来的文件大小比参数length大,则超过的部分会被删除。我们就可以提前使用这个函数提前将文件的大小进行设置这样我们就可以向映射的这块内存进行写入了。下面我们对代码进行一下修改

#include <iostream>
#include <sys/mman.h>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
static const int SIZE = 4096;
int main()
{
    int fd = open("./a.txt", O_RDWR | O_CREAT, 0644);
    truncate("a.txt", 1024);
    if (fd < 0)
    {
        printf("%s\n", strerror(errno));
        return -1;
    }
    char *str = (char *)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    //注意MAP_PRIVATE和MAP_SHARED
    //建立映射
    if (str == MAP_FAILED)
    {
        printf("%s\n", strerror(errno));
        close(fd);
        return -2;
    }
    strcpy(str, "helloworld");
    close(fd);

    return 0;
}

然后我们在运行一下代码:

此时我们发现就成功的将其写入到文件当中了.

四.mmap原理

mmap内存映射的实现过程主要分为三个阶段:

(一):进程启动映射过程并在虚拟地址空间当中为映射创建映射区域

   1.进程在用户空间调用mmap也就是上面那个函数。

   2.在当前进程的地址空间当中寻找一段连续的空虚的虚拟地址

   3.给这块虚拟地址分配一个vm_area_struct的结构并对其各个区域进行初始化

   4.将新键的虚拟结构插入到虚拟地址空间的链表或者红黑树当中

(二):实现物理内存地址和虚拟地址的映射关系

  1.为映射分配了新的虚拟地址空间之后通过待映射的文件描述符指针,在文件描述符表当中找到对应的文件描述符链接到内核已经打开的文件描述符集当中的struct_file,这个struct_file维护着这个被打开的文件的各项信息

  2.通过这个文件的结构体链接到file_operations,调用内核的mmap其函数原型为int mmap(struct file*filp,struct vm_area_struct*vma),请注意不是用户态的mmap

3.内核mmap函数通过虚拟文件系统当中的inode定位到文件的物理地址

4.通过reamp_pfn_range函数建立页表即实现了文件地址和虚拟地址的映射关系。

(三)

1.进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。

2.缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。

3.调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。

4.之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_56999918/article/details/127070280

智能推荐

grpc 入门问题_proto: file does not reside within any path specif-程序员宅基地

文章浏览阅读1.7k次。一. 将.proto 文件编译出java文件1.下载对应系统的protoc;【自用链接:https://pan.baidu.com/s/1yTwRi8CzvnjX9ICRExQpqQ 密码:mrow】2.在proto.exe所在文件目录下打开命令行(shift+右键),执行: protoc -I=E:\tmp --java_out=./ E:\tmp\send_mail...._proto: file does not reside within any path specified using

大数据基础学习-7.Hive-1.1.0_hive-jdbc:pom:1.1.0-cdh5.13.0 mvn-程序员宅基地

文章浏览阅读1.5k次。一、引入Hive原因– 对存在HDFS上的文件或HBase中的表进行查询时,要手工写一堆MapReduce代码– 对于统计任务,只能由懂MapReduce的程序员才能搞定,耗时耗力FaceBook实现并开源Hive,解决海量结构化日志查询– Hive是一个SQL解析引擎,将SQL语句转译成MR Job,然后在Hadoop平台上运行,达到快速开发的目的。Hive一般不会直接接入到业务中使用,从某种意..._hive-jdbc:pom:1.1.0-cdh5.13.0 mvn

cgo的效率 golang_第一课cgo所需环境-程序员宅基地

文章浏览阅读589次。课程目标Window系统下的环境搭建,go的环境配置,MinGW的环境配置Linux系统下的环境搭建,go的环境配置,Linux自带gcc很方便摘要在macOS和Linux下gcc,在window下需要安装MinGW。同时需要保证环境变量CGO_ENABLED被设置为1,这是表示cgo是否被启用状态。在本地构建时CGO_ENABLED默认启用,在交叉构建cgo是默认禁用的。比如交叉构建ARM环境运..._golang cgo 环境变量

spring boot logback 日志多环境配置uat dev prd等及logPath_IS_UNDEFINED问题解决_log4j project.artifactid_is_undefined-程序员宅基地

文章浏览阅读4.3k次。使用自定义日志配置日志多环境配置.https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-custom-log-levelslogging.config 指定自定义logback-xxx.xml配置文件,不要使用logback-spring.xml,因为会出现logPath_IS_U..._log4j project.artifactid_is_undefined

mysql的CHAR和VARCHAR类型_mysql char和varchar-程序员宅基地

文章浏览阅读449次,点赞9次,收藏9次。mysql的CHAR和VARCHAR类型_mysql char和varchar

七款编辑器/笔记工具推荐_笔记编辑软件免费-程序员宅基地

文章浏览阅读2.6k次。小木屋是一款优秀的网站导航。https://wechalet.cn/ 收录国外和国内各类实用网站,内容涵盖国外创意、设计、美食、视频、图片、旅游、文化、音乐等多领域站点资源,提供简单便捷的网上导航服务。而且对于喜欢的页面,还可以添加收藏,导入Chrome书签,可以随时随地查看喜欢的页面。这里可以提交您的网站,让您的网站更容易被用户发现。来申请一波吧!!!一、一款完全免费的记事本软件 - 轻..._笔记编辑软件免费

随便推点

vue项目中树形结构下拉框(vue-treeselect)_vue-treeselect 属性-程序员宅基地

文章浏览阅读8.6k次。1.npm 安装依赖npm install --save @riophae/vue-treeselect2. 在需要使用的组件中引入import Treeselect from '@riophae/vue-treeselect'import '@riophae/vue-treeselect/dist/vue-treeselect.css' components: { Tre..._vue-treeselect 属性

计算机毕业设计Java高校后勤保修系统(源码+系统+mysql数据库+lw文档)_保修系统系统包图-程序员宅基地

文章浏览阅读224次。计算机毕业设计Java高校后勤保修系统(源码+系统+mysql数据库+lw文档)ssm基于uniapp+Vue框架的《露营》App开发与实现。springboot基于springboot的社会公益平台。ssm基于HTML的“牧经校园疫情防控网站”的设计与实现。springboot基于Java的高校教室申请管理系统。JSP客户关系管理系统的设计与实现sqlserver。JSP教学视频点播系统的设计与实现SQLServer。ssm基于HTML的“守护萌宠”网站的设计与实现。_保修系统系统包图

Git常规使用笔记及注意事项了解一下_使用 git的注意事项-程序员宅基地

文章浏览阅读2.5k次。1.先在Git中仓库建立可在github中或码云中搭建 或自己搭建服务器注意设置忽略上传的文件 过滤掉一些文件或文件夹,那么被过滤的内容就不会被git管理,比如: build/: 过滤整个build文件夹; *.class: 过滤所有.class后缀的文件; path/to/local.properties: 过滤具体文件 .gi..._使用 git的注意事项

Spring学习之旅(十一) Spring Web Flow的配置及简单使用_spring flow-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏15次。学习Spring Web Flow的简单使用_spring flow

数据共享和数据开放如何改变世界论文_GW-ICC2019丨数据共享,开启临床研究新模式...-程序员宅基地

文章浏览阅读2.4k次。我们希望帮助参会者对临床研究有更加深入的认识和理解,改善临床研究观念,切实提高临床研究水平。欢迎更多志同道合的研究者加入平台,共享研究数据,挖掘研究更多价值。——首都医科大学附属北京安贞医院 杜昕教授杜昕教授2019年10月10日,心联乔治心脏健康研究所(HHRC)和医咖会联合举办“HHRC-医咖会临床研究培训论坛”,旨在通过临床研究方法学培训和数据共享理念的传递,提高参会者的临床研究水平,助力推..._数据共享和数据开放如何改变世界论文

tas5717php手册,TAS5715 具有扬声器均衡、双频带 DRC 和 DC 保护的 25W 立体声 I2S 音频放大器...-程序员宅基地

文章浏览阅读941次。TAS5715 具有扬声器均衡、双频带 DRC 和 DC 保护的 25W 立体声 I2S 音频放大器The TAS5715 is a 25-W, efficient, digital audio-power amplifier for driving stereo bridge-tied speakers. One serial data input allows processing of ..._tas5717php使用

推荐文章

热门文章

相关标签