linux mmap 内存映射【转】
转自:http://blog.csdn.net/xyyangkun/article/details/7830313
[-]
- mmap vs readwritelseek
- mmap vs malloc
- mmap共享内存进程通信
- 总结
http://www.perfgeeks.com/?p=723
mmap() vs read()/write()/lseek()
通过strace统计系统调用的时候,经常可以看到mmap()与mmap2()。系统调用mmap()可以将某文件映射至内存(进程空间),如此可以把对文件的操作转为对内存的操作,以此避免更多的lseek()与read()、write()操作,这点对于大文件或者频繁访问的文件而言尤其受益。但有一点必须清楚:mmap的addr与offset必须对齐一个内存页面大小的边界,即内存映射往往是页面大小的整数倍,否则maaped_file_size%page_size内存空间将被闲置浪费。
演示一下,将文件/tmp/file_mmap中的字符转成大写,分别使用mmap与read/write二种方法实现。
/* * @file: t_mmap.c */ #include <stdio.h> #include <ctype.h> #include <sys/mman.h> /*mmap munmap*/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { int fd; char *buf; off_t len; struct stat sb; char *fname = "/tmp/file_mmap"; fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { perror("open"); return 1; } if (fstat(fd, &sb) == -1) { perror("fstat"); return 1; } buf = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { perror("mmap"); return 1; } if (close(fd) == -1) { perror("close"); return 1; } for (len = 0; len < sb.st_size; ++len) { buf[len] = toupper(buf[len]); /*putchar(buf[len]);*/ } if (munmap(buf, sb.st_size) == -1) { perror("munmap"); return 1; } return 0; } #gcc –o t_mmap t_mmap.c #strace ./t_mmap open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3 //open,返回fd=3 fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0 //fstat, 即文件大小18 mmap2(NULL, 18, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb7867000 //mmap文件fd=3 close(3) = 0 //close文件fd=3 munmap(0xb7867000, 18) = 0 //munmap,移除0xb7867000这里的内存映射
虽然没有看到read/write写文件操作,但此时文件/tmp/file_mmap中的内容已由www.perfgeeks.com改变成了WWW.PERFGEEKS.COM .这里mmap的addr是0(NULL),offset是18,并不是一个内存页的整数倍,即有4078bytes(4kb-18)内存空间被闲置浪费了。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { int fd, len; char *buf; char *fname = "/tmp/file_mmap"; ssize_t ret; struct stat sb; fd = open(fname, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) { perror("open"); return 1; } if (fstat(fd, &sb) == -1) { perror("stat"); return 1; } buf = malloc(sb.st_size); if (buf == NULL) { perror("malloc"); return 1; } ret = read(fd, buf, sb.st_size); for (len = 0; len < sb.st_size; ++len) { buf[len] = toupper(buf[len]); /*putchar(buf[len]);*/ } lseek(fd, 0, SEEK_SET); ret = write(fd, buf, sb.st_size); if (ret == -1) { perror("error"); return 1; } if (close(fd) == -1) { perror("close"); return 1; } free(buf); return 0; } #gcc –o t_rw t_rw.c open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3 //open, fd=3 fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0 //fstat, 其中文件大小18 brk(0) = 0x9845000 //brk, 返回当前中断点 brk(0x9866000) = 0x9866000 //malloc分配内存,堆当前最后地址 read(3, "www.perfgeeks.com\n", 18) = 18 //read lseek(3, 0, SEEK_SET) = 0 //lseek write(3, "WWW.PERFGEEKS.COM\n", 18) = 18 //write close(3) = 0 //close
这里通过read()读取文件内容,toupper()后,调用write()写回文件。因为文件太小,体现不出read()/write()的缺点:频繁访问大文件,需要多个lseek()来确定位置。每次编辑read()/write(),在物理内存中的双份数据。当然,不可以忽略创建与维护mmap()数据结构的成本。需要注意:并没有具体测试mmap vs read/write,即不能一语断言谁孰谁劣,具体应用场景具体评测分析。你只是要记住:mmap内存映射文件之后,操作内存即是操作文件,可以省去不少系统内核调用(lseek, read, write)。
mmap() vs malloc()
使用strace调试的时候,通常可以看到通过mmap()创建匿名内存映射的身影。比如启用dl(‘apc.so’)的时候,就可以看到如下语句。
mmap2(NULL, 31457280, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0xb5ce7000 //30M
通常使用mmap()进行匿名内存映射,以此来获取内存,满足一些特别需求。所谓匿名内存映射,是指mmap()的时候,设置了一个特殊的标志MAP_ANONYMOUS,且fd可以忽略(-1)。某些操作系统(像FreeBSD),不支持标志MAP_ANONYMOUS,可以映射至设备文件/dev/zero来实现匿名内存映射。使用mmap()分配内存的好处是页面已经填满了0,而malloc()分配内存后,并没有初始化,需要通过memset()初始化这块内存。另外,malloc()分配内存的时候,可能调用brk(),也可能调用mmap2()。即分配一块小型内存(小于或等于128kb),malloc()会调用brk()调高断点,分配的内存在堆区域,当分配一块大型内存(大于128kb),malloc()会调用mmap2()分配一块内存,与堆无关,在堆之外。同样的,free()内存映射方式分配的内存之后,内存马上会被系统收回,free()堆中的一块内存,并不会马上被系统回收,glibc会保留它以供下一次malloc()使用。
这里演示一下malloc()使用brk()和mmap2()。
/* * file:t_malloc.c */ #include <stdio.h> #include <string.h> #include <stdlib.h>int main(int argc, char *argv) { char *brk_mm, *mmap_mm; printf("-----------------------\n"); brk_mm = (char *)malloc(100); memset(brk_mm, '\0', 100); mmap_mm = (char *)malloc(500 * 1024); memset(mmap_mm, '\0', 500*1024); free(brk_mm); free(mmap_mm); printf("-----------------------\n"); return 1; } #gcc –o t_malloc t_malloc.c #strace ./t_malloc write(1, "-----------------------\n", 24-----------------------) = 24 brk(0) = 0x85ee000 brk(0x860f000) = 0x860f000 //malloc(100) mmap2(NULL, 516096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7702000 //malloc(5kb) munmap(0xb7702000, 516096) = 0 //free(), 5kb write(1, "-----------------------\n", 24-----------------------) = 24
通过malloc()分别分配100bytes和5kb的内存,可以看出其实分别调用了brk()和mmap2(),相应的free()也是不回收内存和通过munmap()系统回收内存。
mmap()共享内存,进程通信
内存映射mmap()的另一个外常见的用法是,进程通信。相较于管道、消息队列方式而言,这种通过内存映射的方式效率明显更高,它不需要任务数据拷贝。这里,我们通过一个例子来说明mmap()在进程通信方面的应用。我们编写二个程序,分别是master和slave,slave根据master不同指令进行不同的操作。Master与slave就是通过映射同一个普通文件进行通信的。
/**@file master.c*/ root@liaowq:/data/tmp# cat master.c #include <stdio.h> #include <time.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> void listen(); int main(int argc, char *argv[]) { listen(); return 0; } void listen() { int fd; char *buf; char *fname = "/tmp/shm_command"; char command; time_t now; fd = open(fname, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) { perror("open"); exit(1); } buf = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { perror("mmap"); exit(1); } if (close(fd) == -1) { perror("close"); exit(1); } *buf = '0'; sleep(2); for (;;) { if (*buf == '1' || *buf == '3' || *buf == '5' || *buf == '7') { if (*buf > '1') printf("%ld\tgood job [%c]\n", (long)time(&now), *buf); (*buf)++; } if (*buf == '9') { break; } sleep(1); } if (munmap(buf, 4096) == -1) { perror("munmap"); exit(1); } } /* *@file slave.c */ #include <stdio.h> #include <time.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> void ready(unsigned int t); void job_hello(); void job_smile(); void job_bye(); char get_command(char *buf); void wait(); int main(int argc, char *argv[
linux mmap 内存映射【转】相关推荐
- Linux mmap内存映射
将最近网上搜索的资料统一整理下,方便后续复查. 一.什么是mmap mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一 ...
- linux mmap 内存映射
http://www.perfgeeks.com/?p=723 mmap() vs read()/write()/lseek() 通过strace统计系统调用的时候,经常可以看到mmap()与mmap ...
- linux mmap 内存映射 mmap() vs read()/write()/lseek()
From: http://www.perfgeeks.com/?p=723 通过strace统计系统调用的时候,经常可以看到mmap()与mmap2().系统调用mmap()可以将某文件映射至内存(进 ...
- linux内存管理函数mmap和brk,brk() 和 mmap() 内存映射
参考博文:http://www.cnblogs.com/huxiao-tee/p/4660352.html x86平台下linux进程虚拟地址空间分布(2.6.7以前版本) mmap区域与栈区域相对增 ...
- mmap 内存映射详解
目录 mmap基础概念 mmap内存映射原理 mmap示例代码 mmap和常规文件操作的区别 mmap使用的细节 前言 原文对 mmap 内存映射已经表述的很清楚了,我只是在原文的基础上,附上了 mm ...
- mmap内存映射、system V共享内存和Posix共享内存
linux内核支持多种共享内存方式,如mmap内存映射,Posix共享内存,以system V共享内存.当内核空间和用户空间存在大量数据交互时,共享内存映射就成了这种情况下的不二选择.它能够最大限度的 ...
- mmap内存映射原理
mmap概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系. 特点:实现这样的映射关系后,进程就可以 ...
- mmap(内存映射)和shm(共享存储)
mmap(内存映射)和shm(共享存储): 1.mmap是在磁盘上建立一个文件,每个进程地址空间中开辟出一块空间进行映射. 而对于shm而言,shm每个进程最终会映射到同一块物理内存. shm保 ...
- linux mmap内存文件映射
一.传统文件访问 unix访问文件的传统方法使用open打开他们,如果有多个进程访问一个文件,则每一个进程在再记得地址空间都包含有该文件的副本,这不必要地浪费了存储空间.下面说明了两个进程同时读一个文 ...
最新文章
- 戴尔5598安装系统流程
- linux常见基本命令
- Redis集群搭建-韩国庆
- streamsets rest api 转换 graphql
- raft引入no-op解决了什么问题
- 在windows上Matlab 编译MatConvNet
- linux查询tcp异常,linux服务器内存cpu 流量tcp异常信息记录python脚本
- andpods授权码订单号分享_微信OAuth2授权登录
- 「ECharts」交互 API (echarts、echartsInstance)
- xmlhelper (把实体对象转成xml文档)
- 【emWin】例程五:显示数值
- EA(Enterprise Architecture,企业架构)
- 这位BAT大佬写的Leetcode刷题笔记,让我offer拿到手软
- gdi作图与系统不兼容_技术作图:技能准备amp;物理装备
- 吉比特无源光纤说明书_[干货]光纤通信之缩略语英汉对照表
- 不小心删除了网络适配器中的无线网卡驱动?
- RK3399平台开发系列讲解(硬件波形解析篇)10.1、USB2.0相关硬件波形(实图)解析
- 2020莱斯大学计算机全球排名,2020年QS世界大学排名:美国莱斯大学全球位列第85名...
- 基于Echarts实现可视化数据大屏实时监测大数据
- 华为ai音箱能虚拟服务器吗,华为AI音箱能做什么 华为AI音箱功能详解
热门文章
- Android 的singleLine废弃解决
- android byteBuffer的使用
- 解决mxnet错误:OSError: libcudart.so.10.0: cannot open shared object file: No such file or directory
- Vue 路由router的两种模式
- 洛谷 P3372 【模板】线段树 1(线段树区间加区间找)
- Java小数中的四舍五入
- Win2008 R2 IIS7.5+PHP5(FastCGI)+MySQL5环境搭建教程
- binutils工具集之---nm
- iOS基础知识点总结
- Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.