先放个结论:

  • 内存映射通常比随机访问更快,尤其访问的对象是分离的和不可预测的.
  • 内存映射会持续占用pages, 直到完成访问. 这意味当长时间重度使用一个文件很久之前, 然后你关闭了它, 然后再重新打开, 它会直接cache hit, 文件命中. 而Read方法, 这个文件已经早被flush走了. mmap 用完立马丢弃它, 它把文件映射到了内存上.
  • Read读文件比较简单, 而且比较快.

    总结, 使用mmap: 访问数据随机地, 保存它长时间, 或想着共享给其它进程; Read 适合访问数据连续存储的数据, 或者读完就丢弃掉.

https://stackoverflow.com/questions/45972/mmap-vs-reading-blocks

上述的Stackoverflow上的讨论非常值得阅读,高票下的评论区在争论mmap的开销问题, 尤其是连续的文件读取的性能上.

一.操作数据的两种方式

https://blog.schmichael.com/2011/05/15/sharing-python-data-between-processes-using-mmap/

Usually in the UNIX world you have 2 ways of accessing/manipulating data: memory addresses or streams (files). Manipulating data via memory addresses means pointers, offsets, malloc/free, etc. Stream interfaces manipulate data via read/write/seek system calls for files and send/recv/etc for sockets.

通常在UNIX世界中,有两种访问/操作数据的方式:内存地址或流(文件)。文件的操作大多是基于流操作。

  • 通过内存地址操作数据意味着指针,偏移,malloc / free等。
  • 流接口操作数据通过对文件的系统调用( read/write/seek) 和socket操作(send / recv / etc)。

二.文件操作的两种方式

1. 标准文件I/O

I/O的原理: https://blog.csdn.net/jfengamarsoft/article/details/76216486

I/O请求包括数据从缓冲区排出(写操作)和数据填充缓冲区(读操作)。 每一次IO操作,都会发生用户态--内核态这种 system call。

I/O操作有一个巨大的缺陷,就是当文件很大,比如有1亿行时,如果每读一行都进行一次IO操作,那么,这个系统调用的次数是1亿多次,频繁的IO操作严重影响程序的性能。

2. 内存映射I/O

内存映射意味着将文件加载到内存的用户空间,这意味着内存地址与文件中的字之间存在一对一的对应关系。此资源通常是物理存在于磁盘上的文件,但也可以是设备,共享内存对象或操作系统可通过文件描述符引用的其他资源。一旦存在,文件和存储空间之间的这种相关性允许应用程序将映射部分视为主存储器。程序员可以直接通过内存访问文件,与任何其他内存驻留数据相同 - 甚至可以允许写入内存区域透明地映射回磁盘上的文件。

优点: 如果一个大文件,假设每次进行内存映射50M,那么I/O操作的次数便少了, 提高了I / O性能。

缺点: 对于小文件,内存映射文件会导致浪费空间。因为内存映射始终与页面大小对齐,大多为4 KB。因此,5 KB文件将分配8 KB,因此浪费了3 KB。

3.两个方法的对比:

https://en.wikipedia.org/wiki/Memory-mapped_file

  • 访问内存映射文件比使用直接读写操作更快。首先,系统调用比程序本地内存的简单更改慢几个数量级。其次,在大多数操作系统中,实际映射的内存区域是内核的页面缓存(文件缓存),这意味着不需要在用户空间中创建副本。
  • 只有具有MMU的硬件架构才能支持内存映射文件。在没有MMU的体系结构中,操作系统可以在发出映射请求时将整个文件复制到内存中,但如果只访问文件的一小部分,这将非常浪费和缓慢,并且只能用于文件这将适合可用的内存。

简而言之,内存映射性能更好。由于系统调用开销和内存复制,标准I/O方法成本很高。内存映射文件的另一个常见用途是在多个进程之间共享内存。在现代保护模式操作系统中,通常不允许进程访问分配给另一进程使用的存储器空间,内存映射可以安全地共享内存。

三. python mmap = 内存映射I/O

https://www.safaribooksonline.com/library/view/linux-system-programming/0596009585/ch04s03.html

上面这篇文章很好讲述了mmap的原理: 即

As an alternative to standard file I/O, the kernel provides an interface that allows an application to map a file into memory, meaning that there is a one-to-one correspondence between a memory address and a word in the file. The programmer can then access the file directly through memory, identically to any other chunk of memory-resident data—it is even possible to allow writes to the memory region to transparently map back to the file on disk.

mmap本质上是内存映射。文件被映射到内存之后,这个文件就如同一个字符串变量一样,可以随意的操作,诸如 end/recv/ 等socket操作。

作为标准文件I / O的替代,内核提供了一个允许应用程序将文件映射到内存的接口,这意味着内存地址与文件中的字之间存在一对一的对应关系。然后程序员可以直接通过内存访问文件,与任何其他内存驻留数据相同 - 甚至可以允许写入内存区域透明地映射回磁盘上的文件。

读取和写入内存映射文件可避免在使用read( )或write( )系统调用时发生的无关副本,其中必须将数据复制到用户空间缓冲区和从用户空间缓冲区复制数据。

四. 发生的Bug

mmap读取一个10G 大文件(系统镜像)时, 我犯了一些错误:

1.在使用mmap时,我想当然以为系统会自动的cache, 执行swamp in 和 swamp out。 实际上mmap如果不指定分页数和读取的字节,它会直接读取整个文件。导致随着find的操作不断执行,内存越来越小...这里有个好处是“延迟加载”,因此即使对于非常大的文件也使用少量RAM。 所以当我的的虚拟内存资源变得饱和时,会发生trash(颠簸),从而导致分页状态不变,排除了大多数应用程序级别的处理。这会导致计算机性能下降或崩溃。这种情况可以无限期地持续下去,直到用户关闭某些正在运行的应用程序或活动进程释放额外的虚拟内存资源。

https://stackoverflow.com/questions/31963124/memory-leakish-when-using-re-and-mmap

后来指定读取的offset,解决了这个问题。

offset = 0
length = mmap.ALLOCATIONGRANULARITY * 10 with open(p, "rb") as f:
while offset < file_size:
mm = mmap.mmap(f.fileno(), length=length, offset=offset,
access=mmap.ACCESS_READ)
offset += (mmap.ALLOCATIONGRANULARITY * 10)

2.在使用mmap时,由于mmap中使用了find()操作,它其实是socket操作,在不停地执行该操作时,导致WebSocket被阻塞,不能与前端进行交互。 由于这个原因,我最终还是放弃了mmap。

3.标准文件I/O的read()操作也可以指定字节读取,这是我想当然以为它一次读完了。

mmap vs read的更多相关文章

  1. Python之mmap内存映射模块(大文本处理)说明

    背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力.关于sed的说明可以看了解sed的工作原理,本文将介绍通过 ...

  2. MMAP和DIRECT IO区别

    看完此文,题目不言自明.转自 http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 开发中,有几个关系到性能的东西,技术人员非常关 ...

  3. mmap为什么比read/write快(兼论buffercache和pagecache)

    参考文献: <从内核文件系统看文件读写过程>http://www.cnblogs.com/huxiao-tee/p/4660352.html?utm_source=tuicool& ...

  4. 认真分析mmap:是什么 为什么 怎么用

    mmap基础概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.实现这样的映射关系后,进程就可以采用指 ...

  5. Linux下TomcatVM参数修改:Native memory allocation (mmap) failed to map 3221225472 bytes for committing reserved memory.

    不可行的方法最初我直接修改catalina.sh, 将JAVA_OPTS变量加上了 -server -Xms1G -Xmx1G -XX:+UserG1GC最初看起来没啥问题,但是当服务器运行几天后,发 ...

  6. Python多进程(2)——mmap模块与mmap对象

    本文介绍Python mmap模块与mmap对象的用法. mmap 模块提供“内存映射的文件对象”,mmap 对象可以用在使用 plain string 的地方,mmap 对象和 plain stri ...

  7. epoll里面mmap释疑

    今天看到有文章说epoll里面用了mmap,还说进程不需要从内核读数据,只需要从用户态buffer读数据就可以.觉得很神奇,就查了一下,发现完全不是描述的那样.实际上,只是把要传递的fd通过mmap来 ...

  8. mmap和shm共享内存的区别和联系

    共享内存的创建 根据理论: 1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿 ...

  9. MMAP和DIRECT IO区别【转】

    转自:http://www.cnblogs.com/zhaoyl/p/5901680.html 看完此文,题目不言自明.转自 http://blog.chinaunix.net/uid-2710571 ...

  10. 认真分析mmap:是什么 为什么 怎么用【转】

    转自:http://www.cnblogs.com/huxiao-tee/p/4660352.html?utm_source=tuicool&utm_medium=referral 阅读目录 ...

随机推荐

  1. 查询接口---flask+python+mysql

    环境准备 安装flask pip install  flask 项目结构如图 1.新建配置文件conf.py #!/usr/bin/python# -*- coding:utf-8 -*- impor ...

  2. nginx 设置反向代理

    一.多个路径指向同一ip的不同服务 参考地址:https://www.cnblogs.com/hanmk/p/9289069.html 编辑nginx.conf配置文件,新增加一个server模块,或 ...

  3. Win10下默认显示文件的扩展名

    默认不显示文件的后缀名 1.右击此电脑,点击属性 2.点击控制面板主页 3.点击文件资源管理器选项 4.切换到查看选项卡,取消勾选“隐藏已知文件类型的扩展名”,应用->确定 结果:

  4. 【Linux】bat文件如何执行

    绝对路径,"/home/myDir/xxx.bat" OR 所在的目录,:"./xxx.bat".

  5. MAC上配置idea环境时排查问题

    现象:没有使用走公司maven仓库的setting.xml文件时,只有公司内部依赖 没有找到在idea的maven配置中指定 公司setting.xml后,所有的文件都提示找不到 解决办法:把公司se ...

  6. Browser cannot find PAC because wpad hostname cannot be resolved

    Enterprise Network administrator may faultly forget to configure wpad hostname to DNS server. If use ...

  7. 使用uwsgi+nginx部署项目

    Uwsgi:部署web应用程序 Nginx:反向代理,静态服务器 1.修改uwsgi配置文件>nginx反向代理[nginx接收请求->传递->[uwsgi] http=.. --& ...

  8. PATB1031查验身份证

    这一题遇见的错误有很多,学会了一些知识点 使用了strcpy函数,前是需要复制的数组,后面是被复制的数组 关于字符,如果是非数字可以使用 <='9' && >='0'来判断 ...

  9. (近万字)一篇文章带你了解HTML5和CSS3开发基础与应用-适合前端面试必备

    作者 | Jeskson 来源 | 达达前端小酒馆 HTML5和CSS3开发基础与应用,详细说明HTML5的新特性和新增加元素,CSS3的新特性,新增加的选择器,新的布局,盒子模型,文本,边框,渐变, ...

  10. jenkins pipeline使用方式

    pipeline 使用 使用groovy的一种DSL语言,流程控制 pipeline脚本同其他脚本语言一样,从上到下顺序执行,它的流程控制取决于Groovy表达式,为jenkins用户提供了更巨大的灵 ...