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

Linux下对mmap封装使用

Linux下对mmap封装使用

  • 1、mmap简介
  • 2、Linux下mmap使用介绍
    • 2.1、mmap函数
    • 2.2、munmap函数
  • 3、对mmap进行封装
  • 4、对封装类MEM_MAP进行测试
  • 5、mmap原理
  • 6、源代码下载

1、mmap简介

mmap即memory map,是一种内存映射文件的技术。mmap可以将一个文件或者其它对象映射到进程的地址空间,进而实现磁盘地址和进程虚拟地址的一一对应关系。通过使用mmap技术,我们可以让不同进程通过映射到同一个普通文件的方式实现共享内存,普通文件被映射到进程地址空间当中之后,进程可以向访问普通内存一样对文件高效地进行一系列操作。

2、Linux下mmap使用介绍

2.1、mmap函数

mmap() 必须以 PAGE_SIZE(默认为4KB) 为单位进行映射,而内存也只能以页为单位进行映射,若要映射非 PAGE_SIZE 整数倍的地址范围,要先进行内存对齐,强行以 PAGE_SIZE 的倍数大小进行映射。函数声明如下:

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

参数说明:

  • addr: 映射区的开始地址,设置为0时表示由系统决定映射区的起始地址
  • length: 映射区的长度,长度单位是以字节为单位,不足一内存页按一内存页处理
  • port: 映射区域的权限,不能与文件的打开模式冲突,可以通过or运算合理地组合在一起
  • flags: 映射的标志位,可以通过or运算合理地组合在一起
  • fd: 有效的文件描述词,一般是由open()函数返回
  • offset: 文件偏移量

参数 port 的取值如下:

PORT_EXEC:映射区具有可执行权限
PROT_READ:映射区具有可读权限
PROT_WRITE:映射区具有可写权限
PROT_NONE:映射区不可被访问

参数 flags 的取值如下:

MAP_SHARED:对映射区域的写入操作直接反映到文件当中
MAP_FIXED:若在start上无法创建映射则失败(如果没有此标记会自动创建)
MAP_PRIVATE:对映射区域的写入操作只反映到缓冲区当中不会写入到真正的文件
MAP_ANONYMOUS:匿名映射将虚拟地址映射到物理内存而不是文件(忽略fd)
MAP_DENYWRITE:拒绝其它文件的写入操作
MAP_LOCKED:锁定映射区域保证其不被置换

返回值:成功执行时,mmap() 返回被映射区的指针。失败时,mmap() 返回 MAP_FAILED(其值为(void *)-1),并且 errno 被设为以下的某个值

EACCES:访问出错
EAGAIN:文件已被锁定,或者太多的内存已被锁定
EBADF:fd不是有效的文件描述词
EINVAL:一个或者多个参数无效
ENFILE:已达到系统对打开文件的限制
ENODEV:指定文件所在的文件系统不支持内存映射
ENOMEM:内存不足,或者进程已超出最大内存映射数量
EPERM:权能不足,操作不允许
ETXTBSY:已写的方式打开文件,同时指定 MAP_DENYWRITE 标志
SIGSEGV:试着向只读区写入
SIGBUS:试着访问不属于进程的内存区

2.2、munmap函数

munmap() 声明如下:

#include <sys/mman.h>
int munmap(void* start, size_t length);

参数说明:

  • start: 映射区的指针,即mmap()的返回值
  • length: 映射区的长度

返回值:成功执行时,munmap() 返回0。失败时,munmap() 返回-1。

3、对mmap进行封装

下面给出 MEM_MAP 类的设计:

#ifndef __MEM_MAP_H
#define __MEM_MAP_H#include <iostream>
#include <string>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>class Noncopyable
{
public:Noncopyable() = default;~Noncopyable() = default;Noncopyable(const Noncopyable&) = delete;Noncopyable& operator=(const Noncopyable&) = delete;
};#define MAX_PATH_LEN    200class MEM_MAP : private Noncopyable
{
public:MEM_MAP();~MEM_MAP();//取消映射void unmap();//取消映射并删除对应文件void remove();//映射指定的文件int map(const char* filename,size_t length,int flags = O_RDWR | O_CREAT,mode_t mode = 0644,int prot = PROT_READ | PROT_WRITE,int share = MAP_SHARED,void* addr = NULL,off_t offset = 0);public://将数据立即刷到文件里(MS_ASYNC、MS_SYNC、MS_INVALIDATE)int sync(size_t len, int flags = MS_SYNC);int sync(int flags = MS_SYNC);public://返回基地址void* addr() const;//返回映射大小size_t size() const;//返回文件描述符int fd() const;//返回文件名const char* filename() const;private://mmap基地址void* m_addr;//mmap大小size_t m_length;//mmap文件描述符int m_fd;//mmap文件名char m_filename[MAX_PATH_LEN];
};#endif /*__MEM_MAP_H*/

以下是 MEM_MAP 类各个方法的具体实现:

#include "mem_map.h"MEM_MAP::MEM_MAP(): m_addr(NULL),m_length(0),m_fd(-1)
{memset(m_filename, 0, sizeof(m_filename));
}MEM_MAP::~MEM_MAP()
{unmap();
}void MEM_MAP::unmap()
{if (m_addr != NULL){munmap(m_addr, m_length);}if (m_fd != -1){close(m_fd);}m_addr = NULL;m_length = 0;m_fd = -1;memset(m_filename, 0, sizeof(m_filename));
}void MEM_MAP::remove()
{char filename[MAX_PATH_LEN];strncpy(filename, m_filename, MAX_PATH_LEN);unmap();if (filename[0] != '\0'){unlink(filename);}
}int MEM_MAP::map(const char* filename,size_t length,int flags,mode_t mode,int prot,int share,void* addr,off_t offset)
{//取消旧的映射unmap();//数据赋值m_length = length;strncpy(m_filename, filename, MAX_PATH_LEN);//打开文件描述符m_fd = open(m_filename, flags, mode);if (m_fd == -1){std::cout << strerror(errno) << std::endl;unmap();return -1;}//指定文件大小if (truncate(m_filename, m_length) == -1){std::cout << strerror(errno) << std::endl;unmap();return -2;}//建立映射m_addr = mmap(addr, length, prot, share, m_fd, offset);if (m_addr == MAP_FAILED){std::cout << strerror(errno) << std::endl;m_addr = NULL;unmap();return -3;}return 0;
}int MEM_MAP::sync(size_t len, int flags)
{return msync(m_addr, len, flags);
}int MEM_MAP::sync(int flags)
{return msync(m_addr, m_length, flags);
}void* MEM_MAP::addr() const
{return m_addr;
}size_t MEM_MAP::size() const
{return m_length;
}int MEM_MAP::fd() const
{return m_fd;
}const char* MEM_MAP::filename() const
{return m_filename;
}

4、对封装类MEM_MAP进行测试

测试代码如下,运行之后会生成一个拥有315行 Hello World! 的文件,且末尾会剩余一个字节

#include "mem_map.h"int main(int argc, char* argv[])
{MEM_MAP mmap;if (mmap.map("test.mmap", 4 * 1024) != 0){return -1;}char* str = (char*)mmap.addr();while (1){if (strlen(str) + strlen("Hello World!\n") > mmap.size()){break;}strcat(str, "Hello World!\n");}return 0;
}

5、mmap原理

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

1. 创建映射区域

过程:进程在用户空间调用 mmap() ,此时进程会在当前进程的地址空间当中寻找一段连续的空闲虚拟地址,并给这块虚拟地址分配一个 vm_area_struct 结构(会自动对各个区域进行初始化),然后将新键的虚拟结构插入到虚拟地址空间的链表或者红黑树当中。

2. 实现物理内存地址和虚拟地址的映射关系

过程:通过待映射的文件描述符指针,在文件描述符表当中找到对应的文件描述符链接到内核已经打开的文件描述符集当中的 struct_file,这个 struct_file 维护着这个被打开的文件的各项信息,通过这个文件的结构体链接到 file_operations,调用内核的mmap函数(原型为 int mmap(struct file* filp, struct vm_area_struct* vma),注意这个不是用户态的mmap),内核mmap函数通过虚拟文件系统当中的inode定位到文件的物理地址,通过 reamp_pfn_range() 建立页表即实现了文件地址和虚拟地址的映射关系。

3. 实现虚拟地址上的数据同步到磁盘文件中

过程:进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上,因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用 nopage() 把所缺的页从磁盘装入到主存中,之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址(由 flags 参数决定是否会自动回写),即完成了写入到文件的过程。

6、源代码下载

下载地址:mmap封装测试代码

相关文章:

Linux下对mmap封装使用

Linux下对mmap封装使用 1、mmap简介2、Linux下mmap使用介绍2.1、mmap函数2.2、munmap函数 3、对mmap进行封装4、对封装类MEM_MAP进行测试5、mmap原理6、源代码下载 1、mmap简介 mmap即memory map&#xff0c;是一种内存映射文件的技术。mmap可以将一个文件或者其它对象映射到进…...

深入了解云计算:发展历程、服务与部署模型、未来趋势与挑战

开篇博主 bluetata 的观点&#xff1a;PaaS 服务必将是未来10年云计算权重最高的趋势&#xff08;05/02/2023 15:32&#xff09; 文章目录 一、前言二、认识了解云计算2.1 什么是云计算2.1.1 维基百科上的云计算定义2.1.2 NIST 标准云计算定义2.1.3 如果被面试如何解释云计算 2…...

使用乐鑫 Web IDE 助力物联网开发

乐鑫 Web IDE 是基于 Eclipse Theia 的框架&#xff0c;支持 ESP-IDF VS Code 插件同时具备多项辅助工具。您可以观看我们在 Espressif DevCon22 上的演示视频​​​​​​​&#xff0c;了解它的实际应用。 【乐鑫开发者大会-21】搭载 ESP-IDF Visual Studio Code 插件的乐鑫 …...

Maven(5)---Maven的部署和发布

Maven的部署和发布 在前面的博客中&#xff0c;我们已经学习了Maven的基础知识、依赖管理、插件和生命周期&#xff0c;以及多模块项目管理。本篇博客将介绍Maven的部署和发布功能。 什么是部署和发布 在软件开发过程中&#xff0c;部署和发布是非常重要的环节。部署是指将软…...

内网渗透之权限维持-黄金白银票据隐藏账户远控-RustDeskGotoHTTP

0x01权限维持-隐藏用户 CreateHiddenAccount工具 CreateHiddenAccount -u test -p Psswrd用户管理能查看到&#xff0c;命令查看看不到&#xff0c;单机版无法删除(不在任何组)&#xff0c;域环境(在administrator组中)可以删除 0x02权限维持-黄金白银票据 ⻩⾦票据⽣成攻…...

动态规划——带权活动选择

带权活动选择Time Limit: 3000 MSMemory Limit: 1000 KB Description 给定n个活动&#xff0c;活动ai表示为一个三元组(si,fi,vi)&#xff0c;其中si表示活动开始时间&#xff0c;fi表示活动的结束时间&#xff0c;vi表示活动的权重, si<fi。带权活动选择问题是选择一些活…...

软考A计划-真题-分类精讲汇总-第十八章(面向对象程序设计)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…...

【C++ 入坑指南】(09)数组

文章目录 简介一维数组1. 定义2. 特点3. 用途4. 示例 二维数组1. 定义2. 用途3. 示例 简介 C 支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。 一维数组 1. 定义…...

Vue.js

文章目录 Vue&#xff08;前端框架&#xff09;data基本语法v-bind&#xff08;属性&#xff09;v-if&#xff08;条件&#xff09;v-formethods事件v-model表单绑定todolist&#xff08;添加删除展示内容&#xff0c;含上下移动&#xff09;es6语法生命周期函数axios发送ajax请…...

博士毕业答辩流程 注意事项

前言&#xff1a;2023年5月17日14:00-17:00&#xff0c;与实验室其他同学一起旁听了本实验室的博士论文答辩。接下来&#xff0c;我对博士毕业答辩的大致流程进行简要介绍&#xff0c;并对个环节的注意事项进行总结归纳&#xff0c;供毕业生参考。 目录 1. 准备阶段2. 汇报期间…...

拼多多开放平台订单详情接口解析

API接口订单接口是指用于实现订单相关操作的程序接口。通过这个接口&#xff0c;用户可以实现创建、修改、查询和取消订单等功能。 常见的API接口订单接口包括&#xff1a; 创建订单接口&#xff0c;用于实现用户下单操作。 修改订单接口&#xff0c;用于修改已有订单信息。 …...

如何把ipa文件(iOS安装包)安装到iPhone手机上? 附方法汇总

苹果APP安装包ipa如何安装在手机上&#xff1f;很多人不知道怎么把ipa文件安装到手机上&#xff0c;这里就整理了苹果APP安装到iOS设备上的方式&#xff0c;仅供参考 苹果APP安装包ipa如何安装在手机上&#xff1f;使用过苹果手机的人应该深有感触&#xff0c;那就是苹果APP安…...

由浅入深了解 深度神经网络优化算法

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 导言 优化是从一组可用的备选方案中选择最佳方案。优化无疑是深度学习的核心。基于梯度下降的方法已经成为训练深度神经网络的既定方法。 在最简单的情况下&#xff0c;优化问题包括通过系统地从允许集合中…...

LIN-报文结构

文章目录 协议规范一、字节场二、报文头&#xff08;HEADER FIELDS&#xff09;同步间隔&#xff08;synchronisation break)同步场&#xff08;SYNCH FIELD&#xff09;标识符场&#xff08;IDENTIFIER FIELD&#xff09; 三、数据场&#xff08;DATE FIELDS&#xff09;四、校…...

南京邮电大学通达学院2023c++实验报告(三)

题目 实验题目1 某公司财务部需要开发一个计算雇员工资的程序。该公司有3类员工,工资计算方式如下: (1)工人工资:每小时工资额(通过成员函数设定)乘以当月工作时数(通过成员函数设定),再加上工龄工资。 (2)销售员工资:每小时工资额(通过成员函数设定)乘以当月…...

ISO9000和ISO9001有哪些区别?

作为ISO标准体系的新手&#xff0c;ISO9000和ISO9001是第一个接触到的标准。有些人可能会含糊地表达包含关系的词语&#xff0c;但他们仍然无法真正理解它们。两者的关系是什么&#xff1f;有什么区别&#xff1f;事实上&#xff0c;两者的主要区别体现在以下三个方面: 第一&am…...

第7章异常、断言和曰志

Java和C异 在C中&#xff0c;throw说明符在运行时执行。Java在编译时执行。 处理错误 异常处理的任务就是将控制权从产生错误的地方转移到能够处理这种情况的错误处理器。 如果由于出现错误而使得某些操作没有完成&#xff0c;程序应该&#xff1a;返回到一种安全状态&#…...

springboot读取和写入csv文件数据

前言 csv格式的表格&#xff0c;和xls以及xlsx格式的表格有一些不同&#xff0c;不能够直接用处理xls的方式处理csv&#xff1b; 以下我将介绍如何读取并写入csv数据 准备工作 要处理csv格式的表格数据&#xff0c;我们首先需要引入pom.xml的依赖 <dependency><art…...

【产品经理】工作交接

一、前言 相信大家对这样的场景一定不陌生&#xff1a;有一天去找某个业务的负责人&#xff0c;突然被告知调岗了&#xff0c;或是辞职了&#xff0c;更坏的情况是&#xff0c;甚至完全找不到相关人员了&#xff0c;直接导致工作搁置了。这种情况&#xff0c;你应该多少会感到…...

Springer期刊 latex投稿经验分享

Springer Nature期刊的latex模板下载: Download the journal article template package 以MTAP为例(修改之后对修订稿的投递过程) 第一步:将您的文章提交到适当的期刊轨道或特刊。 如有必要,从下拉菜单中更改您提交的文章类型。 然后点击Proceed 第二步: 与您提交的先前修…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案

一、延迟敏感行业面临的DDoS攻击新挑战 2025年&#xff0c;金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征&#xff1a; AI驱动的自适应攻击&#xff1a;攻击流量模拟真实用户行为&#xff0c;差异率低至0.5%&#xff0c;传统规则引…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

CMS内容管理系统的设计与实现:多站点模式的实现

在一套内容管理系统中&#xff0c;其实有很多站点&#xff0c;比如企业门户网站&#xff0c;产品手册&#xff0c;知识帮助手册等&#xff0c;因此会需要多个站点&#xff0c;甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...