先放个结论:

  • 内存映射通常比随机访问更快,尤其访问的对象是分离的和不可预测的.
  • 内存映射会持续占用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. 201871010135 张玉晶 《面向对象程序设计(java)》第二周学习总结

    201871010135 张玉晶 <面向对象程序设计(java)>第二周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  2. NOIP 2008 笨小猴

    洛谷 P1125 笨小猴 洛谷传送门 JDOJ 1539: [NOIP2008]笨小猴 T1 JDOJ传送门 Description 笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼.但是他找到 ...

  3. JDOJ 1133 分段公司利润

    JDOJ 1133: 分段公司利润 JDOJ传送门 Description 企业发放的奖金根据利润提成.利润低于或等于100000元的,奖金可提10%; 利润高于100000元,低于200000元(1 ...

  4. 5分钟使用docker搭建一个WordPress

    环境为已安装Docker Destop的Windows系统. 过程 使用Docker拉去官方WordPress镜像再进行简单配置是可行的, 但是这里我们使用docker-compose,它会自动根据你 ...

  5. 为什么说JAVA程序员必须掌握SpringBoot?

    原文链接:https://w.url.cn/s/AuDahfb SpringBoot 2.0 的推出又激起了一阵学习 SpringBoot 热,那么, SpringBoot 诞生的背景是什么?Spri ...

  6. Pandas之csv文件对列行的相关操作

    1.Pandas对数据某一列删除 1.删除列 import pandas as pd df = pd.read_csv(file) #axis=1就是删除列 df.drop(['列名1','列名2'] ...

  7. Linux配置DNS

    vi /etc/resolv.conf, 后面加上nameserver 114.114.114.114

  8. docker nginx-php容器镜像瘦身优化

    1. 在安装好php环境的容器,参考上面贴出的链接那篇文章的部分,做好基础工作: #创建工作目录 mkdir /rootfs #进入工作目录 cd /rootfs #创建基础目录 mkdir -p b ...

  9. 【06月18日】A股滚动市净率PB历史新低排名

    2010年01月01日 到 2019年06月18日 之间,滚动市净率历史新低排名. 上市三年以上的公司,2019年06月18日市净率在30以下的公司. 来源:A股滚动市净率(PB)历史新低排名. 1 ...

  10. visual studio code 执行 sp1 文件

    需要安装插件PowerShell 如提示 Unsupported PowerShell version 2.0, language features are disabled  (不支持的PowerS ...