先放个结论:

  • 内存映射通常比随机访问更快,尤其访问的对象是分离的和不可预测的.
  • 内存映射会持续占用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. vmware-vmx.exe进程应该怎么杀掉

    如何解决VMware-vmx.exe无法彻底删除的问题 遇见的问题就是 虚拟机一直黑屏,强制关机之后,无法再次打开的问题. 显示:无法创建新虚拟机: 无法打开配置文件 以独占方式锁定此配置文件失败.另 ...

  2. 11-C#笔记-函数-方法

    # 1 函数基本使用 函数的调用方法用C++. 主函数要在一个Class中,静态的,无返回值: 见示例 using System; namespace CalculatorApplication { ...

  3. .Net Core 获取项目所有程序集,排除Microsoft、Nuget下载的

    https://www.cnblogs.com/yanglang/p/6866165.html public static List<Assembly> BaiqianAssemblies ...

  4. python 识别二维码内容的方法

    识别二维码链接的方式有多种,那么如何用python 的方法实现识别呢? 请看如下代码: from pyzbar.pyzbar import decode from PIL import Image i ...

  5. Pandas | 05 基本功能

    到目前为止,我们了解了三种Pandas数据结构以及如何创建它们.接下来将主要关注数据帧(DataFrame)对象,因为它在实时数据处理中非常重要,并且还讨论其他数据结构. 一.系列基本功能 编号 属性 ...

  6. CSS基础以及兼容IE方法

    1 介绍一下标准的CSS的盒子模型?与低版本IE的盒子模型有什么不同的? 标准盒子模型:宽度=内容的宽度(content)+ border + padding + margin低版本IE盒子模型:宽度 ...

  7. .net项目发布到iis

    参考: https://www.cnblogs.com/teyigou/p/8125379.html https://www.cnblogs.com/kissfu/p/6399472.html htt ...

  8. java信号量

    维基百科解释的信号量概念如下 信号量(英语:semaphore)又称为信号标,是一个同步对象,用于保持在0至指定最大值之间的一个计数值.当线程完成一次对该semaphore对象的等待(wait)时,该 ...

  9. org.Hs.eg.db

    bioconduction 主页 http://www.bioconductor.org/packages/release/data/annotation/html/org.Hs.eg.db.html ...

  10. c++primer(第五版) 阅读笔记

    快速阅读一遍c++ primer,复习c++ 1.本书代码:http://www.informit.com/store/c-plus-plus-primer-9780321714114 2.本书结构: