Linux内存映射函数mmap与匿名内存块

news2024/11/18 7:24:00

学习系列:《APUE14.8》《CSAPP9.8.4》

1 总结

  • memory-mapped io可以将文件映射到内存中的buffer,当我们从buffer读写数据时,其实操作的是对应文件中的数据。这样可以达到不使用READ/WRITE的IO操作。
  • mmap也可以直接映射匿名内存块,无需提供文件fd,直接申请一块内存给当前进程使用,也可以选择继承给子进程。注意匿名映射不会真的创建文件,只是拿到了一块填充0的内存。
  • 与共享内存这种传统IPC相比,mmap匿名内存更为灵活,Postgresql使用的共享内存全部是用mmap申请的,只用共享内存申请一个PGShmemHeader结构的大小。

2 文件映射实例

gcc -o main1 -Wall -g -ggdb -O0 -g3 -gdwarf-2 main1.c

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

#include <fcntl.h>
#include <sys/mman.h>

#define COPYINCR (1024 * 1024 * 1024) /* 1 GB */

int main(int argc, char *argv[])
{
	int fdin, fdout;
	void *src;
	void *dst;
	size_t copysz;
	struct stat sbuf;
	off_t fsz = 0;

	if (argc != 3)
	{
		printf("usage: %s <fromfile> <tofile>\n", argv[0]);
		exit(1);
	}

	if ((fdin = open(argv[1], O_RDONLY)) < 0)
	{
		printf("can't open %s for reading\n", argv[1]);
	}

	if ((fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
	{
		printf("can't creat %s for writing\n", argv[2]);
	}

	if (fstat(fdin, &sbuf) < 0) /* need size of input file */
	{
		printf("fstat error\n");
	}

	if (ftruncate(fdout, sbuf.st_size) < 0) /* set output file size */
	{
		printf("ftruncate error\n");
	}

	while (fsz < sbuf.st_size)
	{
		if ((sbuf.st_size - fsz) > COPYINCR)
		{
			copysz = COPYINCR;
		}
		else
		{
			copysz = sbuf.st_size - fsz;
		}

		if ((src = mmap(0, copysz, PROT_READ, MAP_SHARED, fdin, fsz)) == MAP_FAILED)
		{
			printf("mmap error for input\n");
		}
		printf("src: %p\n", (char *)src);
		if ((dst = mmap(0, copysz, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, fsz)) == MAP_FAILED)
		{
			printf("mmap error for output\n");
		}
		printf("dst: %p\n", (char *)src);
		memcpy(dst, src, copysz); /* does the file copy */
		munmap(src, copysz);
		munmap(dst, copysz);
		fsz += copysz;
	}
	exit(0);
}

// gcc -o main1 -Wall -g -ggdb -O0 -g3 -gdwarf-2 main1.c

执行结果:

[mingjie@centos ~/proj/mmap]$ gcc -o main1 -Wall -g -ggdb -O0 -g3 -gdwarf-2 main1.c
[mingjie@centos ~/proj/mmap]$ ./main1 a.data b.data
src: 0x7fde70798000
dst: 0x7fde70798000
[mingjie@centos ~/proj/mmap]$ cat a.data 
aaaaaaaa
bbb
[mingjie@centos ~/proj/mmap]$ cat b.data 
aaaaaaaa
bbb

3 mmap参数说明

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


// 实例1中:
mmap(0, copysz, PROT_READ, MAP_SHARED, fdin, fsz)
mmap(0, copysz, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, fsz)
  • addr:返回映射的起始地址。
    • 这个一般传0进去,让系统返回一个地址。
    • 注意映射出来的空间地址也是类似堆,是从低向高生长的。
  • length:表示需要映射多大的空间。
  • prot:读写标志位
  • flags:
    • MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
    • MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
    • MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
    • MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
    • MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
    • MAP_HUGETLB 使用内存大页。

申请在堆和栈中间的位置:
在这里插入图片描述

4 匿名内存块映射(Postgresql中的mmap)

CreateAnonymousSegment
  ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,  PG_MMAP_FLAGS | mmap_flags, -1, 0);
  • PG_MMAP_FLAGS
    • MAP_SHARED
    • MAP_ANONYMOUS
  • mmap_flags
    • MAP_HUGETLB

效果:

  • 每次调用都会创建一个新的映射。
  • 子进程继承父进程的映射。
  • 当共享映射的其他人在共享映射上写入时,没有fork的copy-on-write机制:写的就是一份数据。

匿名映射的优点:

  • 没有虚拟地址空间碎片,取消映射后,内存立即归还给系统。
  • 与全局堆分开。
  • 可以给子进程继承使用。

匿名映射的缺点:

  • 不能调整大小!
  • 每个映射的大小都是系统页面大小的整数倍,因此会导致地址空间的浪费。
  • 创建和返回映射比预分配的堆产生更多的开销。

5 匿名内存块使用实例(Postgresql中的mmap方式实例)


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	/*Pointer to shared memory region*/
	int *addr;

	addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	if (addr == MAP_FAILED)
	{
		fprintf(stderr, "mmap() failed\n");
		exit(EXIT_FAILURE);
	}

	*addr = 1;

	/*Parent and child share mapping*/
	switch (fork())
	{
	case -1:
		fprintf(stderr, "fork() failed\n");
		exit(EXIT_FAILURE);

	case 0:
		/*Child: increment shared integer and exit*/
		printf("Child started, value = %d, ++value\n", *addr);
		(*addr)++;

		if (munmap(addr, sizeof(int)) == -1)
		{
			fprintf(stderr, "munmap()() failed\n");
			exit(EXIT_FAILURE);
		}
		exit(EXIT_SUCCESS);

	default:
		/*Parent: wait for child to terminate*/
		if (wait(NULL) == -1)
		{
			fprintf(stderr, "wait() failed\n");
			exit(EXIT_FAILURE);
		}

		printf("In parent, value = %d\n", *addr);
		if (munmap(addr, sizeof(int)) == -1)
		{
			fprintf(stderr, "munmap()() failed\n");
			exit(EXIT_FAILURE);
		}
		exit(EXIT_SUCCESS);
	}
}

// gcc -o main3 -Wall -g -ggdb -O0 -g3 -gdwarf-2 main3.c

执行结果

[mingjie@centos ~/proj/mmap]$ ./main3
Child started, value = 1, ++value
In parent, value = 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零信任对企业安全防护能起到什么作用?

随着网络攻击的不断演变&#xff0c;变得更加普遍和复杂&#xff0c;企业正在寻找一种基于身份的网络安全新方法。这些策略和解决方案旨在保护企业内的所有人和机器&#xff0c;并用于检测和防止身份驱动的违规行为。 企业很容易被感染&#xff0c;但问题在于如何找到解决方案。…

基于花朵授粉算法的无线传感器网络部署优化附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

hadoop集群安装(二):克隆服务器集群并免密

文章目录说明分享集群构建集群规划角色划分配置主机名、ip和主机名映射ssh免密总结说明 已 上篇 创建模型虚拟机为基础构建hadoop集群 分享 大数据博客列表开发记录汇总个人java工具库 项目https://gitee.com/wangzonghui/object-tool 包含json、string、集合、excel、zip压缩…

美食杰项目 -- 个人主页(四)

目录前言&#xff1a;具体实现思路&#xff1a;步骤&#xff1a;1. 展示美食杰菜谱大全效果2. 引入element-ui3. 代码总结&#xff1a;前言&#xff1a; 本文给大家讲解&#xff0c;美食杰项目中 实现个人主页的效果&#xff0c;和具体代码。 具体实现思路&#xff1a; 判断是…

如何复用ijkplayer库实现ffmpeg的功能

ijkplayer库介绍 现在ijkplayer播放器应用的非常广泛&#xff0c;很多播放器基本上都是基于ijkplayer二次迭代开发的&#xff0c;众所周知&#xff0c;ijkplayer是基于ffplay的&#xff0c;所以要使用ijkplayer&#xff0c;就必须使用三个so库。 jeffmonyJeffMonydeMacBook-P…

MySQL Server 和 MySQL Workbench安装

对于开发人员来说&#xff0c;只需要安装 MySQL Server 和 MySQL Workbench 这两个软件&#xff0c;就能满足开发的需要了。 ⚫ MySQL Server&#xff1a;专门用来提供数据存储和服务的软件。 ⚫ MySQL Workbench&#xff1a;可视化的 MySQL 管理工具&#xff0c;通过它&#…

会议信息管理系统SSM记录(四)

目录&#xff1a; &#xff08;1&#xff09;部门管理&#xff1a;查询-添加-删除 &#xff08;2&#xff09;部门管理&#xff1a;修改 &#xff08;1&#xff09;部门管理&#xff1a;查询-添加-删除 在DepartmentController中添加方法&#xff1a; 这里getAllDeps方法上篇…

Charles模拟弱网

Charles模拟弱网&#xff0c;适用PC端和移动端&#xff08;IOS&#xff0f;Android&#xff09; 1.打开Proxy->Throttle Settings&#xff0c;以charles 4.2版本为例 2.出现Throttling的界面 3.预设那里有Charles常用的网络设置模拟的数据&#xff0c;根据需要自己选择即可…

【js学习】闭包理解

闭包原理 js使用的是词法作用域&#xff0c;词法作用域的意味着函数执行使用的是定义函数时生效的变量作用域。即函数执行时&#xff0c;里面的参数访问跟执行函数时的作用域无关。如下代码2所示最后输出的是local scope。 闭包定义&#xff1a;js函数对象的内部状态不仅要包…

神经网络的基本工作原理——机器学习

目录 ​编辑 一、实验内容 二、实验过程 1、算法思想 2、算法原理 3、算法分析 三、源程序代码 四、运行结果及分析 五、实验总结 一、实验内容 掌握神经元细胞的数学模型&#xff1b;理解并掌握神经网络的训练过程&#xff1b;理解并掌握神经网络中的矩阵运算&#xff…

Neo4j入门实战

1.介绍 2.实战 Neo4j的sql语句 1.创建多个节点 CREATE (:student {name:小张,age:20}),(:student {name:彭莎丽,age:18})2.匹配节点将节点删除 这样删除是将student中的条件节点删除——>会变成空白节点 match (m:student {name:"Fairy同学"}) remove m:stu…

Docker数据管理

目录 一、数据卷 二、数据卷容器 三、容器互联 管理 Docker容器中数据主要有两种方式&#xff1a; 数据卷&#xff08;Data Volumes&#xff09;数据卷容器&#xff08;DataVolumes Containers&#xff09; 一、数据卷 数据卷是一个供容器使用的特殊目录&#xff0c;位于容…

设计模式之美——基于接口编程

抽象类在被继承时体现的是 is-a 关系&#xff0c;接口在被实现时体现的是 can-do 关系 例如&#xff0c;Plane can fly. Bird can fly&#xff0c;应该把 fly 定义成一个接口。 – 参考 《码出自效Java 开发手册》 函数的命名不能暴露任何实现细节。比如&#xff0c; uploadT…

集合类ArrayList的扩容机制详解

ArrayList类的内部对构造方法进行了重载&#xff0c;提供了无参构造和有参构造两种构造方法。在ArrayList类的内部维护了一个elementData数组用来存放添加的对象。(关于transient关键字&#xff1a;该关键字修饰的属性&#xff0c;不会进行串行化、序列化)。 目录 无参构造扩容…

胡编乱造的自我介绍

写在前面&#xff1a;这篇文章的内容纯属胡编乱造 切勿信以为真。 一、 姓&#xff1a;&#xff08;Black) 布莱克 名&#xff1a;&#xff08;Sirius) 天狼星 中间名&#xff1a;(Orion) 奥莱恩 结束&#xff01; 二、于 2022年3月 入读清华大学信息技术系硕士 &#xff01; 结…

harbor 安装

harbor 安装一.离线安装helm1.下载安装包&#xff0c;上传到服务器2.解压4.验证二.安装harbor1.导入 Harbor源2.下载 Harbor Helm目录3.解压缩4.修改 Harbor Values文件5.部署 Harbor6.访问 Harbor7.验证8.修改daemon.json9.登录Harbor、并push镜像验证10.登录Harbor页面验证是…

基站交直流配电多回路无线智能电量采集监控装置

【摘要】介绍了安科瑞两款多回路无线智能电量采集监控装置&#xff0c;可应用于基站的交直流配电监控、低压出线开关柜集中监控、末端配电箱等集成电力参数监测、电能计量、环境温湿度监测以及无线传输的各类应用场景。 【关键词】无线监控&#xff1b;多回路监控&#xff1b;铁…

OpenFeign源码2-Bean注册过程和调用过程

0. 环境 nacos版本&#xff1a;1.4.1Spring Cloud : Hoxton.SR9&#xff08;没用2020.0.2版本后面说明&#xff09;Spring Boot &#xff1a;2.4.4Spring Cloud alibaba: 2.2.5.RELEASESpring Cloud openFeign 2.2.2.RELEASE 测试代码&#xff1a;github.com/hsfxuebao/s… 20…

深入理解java虚拟机:虚拟机类加载机制(1)

文章目录1. 类加载的时机2. 类加载的过程2.1 加载2.2 验证2.3 准备2.4 解析2.5 初始化1. 类加载的时机 类从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期包括了&#xff1a; 加载&#xff08;Loading&#xff09;验证&#xff08;Verif…

计算机网络-应用层(文件传输协议(FTP协议),电子邮件系统(SMTP协议,MIME,POP3,IMAP协议))

文章目录1. 文件传输协议2. 电子邮件系统1. 文件传输协议 文件传输协议&#xff1a; 文件传送协议FTP&#xff1a;提供不同种类主机系统&#xff08;硬、软件体系等都可以不同&#xff09;之间的文件传输能力。简单文件传送协议TFTP&#xff1a;使用于UDP环境&#xff0c;代码…