关于内存映射文件

AgedBOY 2007-07-07 01:35:51
本贴的主题是:到底为什么,用内存映射来处理大文件,会比直接使用文件IO更快?

------------

以前因为需要共享数据,用过内存映射文件。

但是由于时间仓促、自己懒惰,对于这个机制没有深究。反正开发任务搞定,就算完事。当时自己心里鲁莽的臆测:内存映射文件的APIs,无非是建立在基本文件IO APIs基础之上的,更高级的APIs而已。

前两天看到这里一篇帖子:《用C语言读取大文件的问题》。作者要读写很大的磁盘文件,单个文件上G(这在遥感图像处理领域很稀松平常)。他说用基本的文件IO APIs特别慢。随后有很多网友提出要用内存映射文件APIs来解。

我胡乱了骂了一通,结果大家还是给足了我面子——没理我。我的回帖的主要意思是,文件不管大小都要用基本文件IO APIs来读写,与内存映射无关。当然,暗含的意思就是内存映射APIs最终也使用文件IO APIs来完成工作。

这是我一直以来的一个认识。但看来不太对头。

有人建议我看《Windows核心编程》相关内容。我看了,临时在网上抓的电子版,主要是着急想找到答案。但是看完后,发现并没有令我满意的答复。书中绝对没有详细讲,“到底为什么,用内存映射来处理大文件,会比直接使用文件IO更快”。绝对没有。

书中讲“可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I / O操作,并且可以不必对文件内容进行缓存”。这是被网友引用最多的一段话。

我想这段话是想说“使用内存映射APIs后,用户可以不再调用文件IO APIs,也能读写文件中的数据”。

但看来很多人便理解为“使用内存映射APIs后,(软件系统,甚至包括硬件)就可以不进行实际的文件读写操作,但是也能让用户读写文件数据”。因为他们推出结论“所以用内存映射操作文件,要比文件IO APIs更快”。

我并不是杜撰人们的想法。比如根据我google发现,网上有人说“内存映射文件直接将文件的地址映射到进程的地址空间中,那么操作文件就相当于在内存中操作一样,省去了读和写I/O的时间;第二种方式(指文件IO API方式)是必须这么做(READFILE,WRITEFILE),这个过程是很慢的。”(http://www.xiaozhou.net/ReadNews.asp?NewsID=953)

我暂时坚信这是错误并且可笑的。物理磁盘读写耗时,无论如何不可能省略。物理磁盘上的比特,不可能穿越一个时空奇点直接跳到用户的Buffer中。是啊,在不看鬼片时,我还是个唯物主义者,不相信神话。

那么,“到底为什么,用内存映射来处理大文件,会比直接使用文件IO更快”?

我能想出唯一鲁莽臆测是:人们使用文件IO APIs时,一般是使用默认的系统缓存方式(即 不 指定“FILE_FLAG_NO_BUFFERING”选项),这样一来,磁盘数据实际是先到达一个系统缓存,然后才被复制到用户缓冲区里。你看看FILE_FLAG_NO_BUFFERING的限制就可以猜出,对于缓存方式顺序读写文件来说,假如用户不按照FILE_FLAG_NO_BUFFERING的限制来读写,那么系统势必会采用算法,来将用户的“无礼要求”转换为系统更偏爱的“合理要求”。有了这个“转换-复制”过程的文件读写,之于纯粹的磁盘IO,必将占用更多时间。而内存映射,恐怕是使用非缓冲模式的,设置映射窗口的位置、大小限制与FILE_FLAG_NO_BUFFERING的限制有些类似,所以我猜想内存映射是非缓冲的。所以才会更快。而且不但非缓冲,也没有“系统缓冲到用户缓冲”的复制过程,所以显得快一些吧。

有没有高手可以给出正解?我还是不太相信自己的臆测。臆测毕竟是臆测。
...全文
502 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
JohnHealy 2012-07-07
  • 打赏
  • 举报
回复
楼主需要了解:
1.系统对硬盘的管理(fat32...)
2.系统对内存页面的管理.
3.硬盘的工作原理
4.文件映射的过程


CreateFile-->获取硬件资源(这里是磁盘资源),并得到系统分配的资源使用标识(ID)
CreateFileMapping-->将资源的具体访问位置系统化地置于的内存管理上,并得到系统分配资源的管理标识(ID)
MapViewOfFile-->使用该资源.

产生的结果-->直接使用内存资源,并且由文件映射技术,当硬盘磁头到达该扇区时,看看是否需要写入/读出的事件,如有则执行(这时发生i/o),并且很重要的是,系统扇区是基于(4k大小 fat32,ntff),页面是基于4k大小,如你的内存使用也是基于4k大小分的话,效果很明朗了.(ps:参考orcal,mysql等数据文件的文件定义,就知道不少的内幕).
faith2ocean 2012-03-07
  • 打赏
  • 举报
回复


其实是翻译的不好,“memorymapping” 翻成了 “映射”

不如直接叫“就地画地图”更直接了当,呵呵


faith2ocean 2012-03-07
  • 打赏
  • 举报
回复


映射是直接有虚拟内存管理器接管文件磁盘的物理地址,也就是说系统在后台,直接加出了一块虚拟内存。和其他虚拟内存一样使用。

和一般文件读写io不同的是,不用通过cpu。直接由dma 经北桥传递。
AgedBOY 2007-07-09
  • 打赏
  • 举报
回复
那么根据feimingbiao说的,更快的原因是:

1,节省内存拷贝时间:内存映射没有从系统缓存到用户缓存的复制过程,类似于用户直接读写系统缓存了。
2,更好的磁盘IO策略:内存映射设计了更加精巧的磁盘IO,以及数据缓存策略,甚至包括读写预测及优化等等,往往比用户简单的一块一块的Buffer交换要快。因为后者往往不精巧。
3,在文件中处理一笔数据,速度瓶颈其实不主要在物理磁盘的IO上面,而在于内存中的各种处理。

好吧……虽然这样的解释仍然没有精确到科学的程度,但至少到达实用的程度了。若是真给我Windows的MM源代码看,我还未必有足够的精力和脑力去研究~^_^

非常感谢feimingbiao和牙医。看来feimingbiao在MM方面的研究真是深了去了。偶遇高手,精神为之一震。
feimingbiao 2007-07-09
  • 打赏
  • 举报
回复
牙医:
基本的IO肯定是少不了。要提高IO速度,用一个好的缓存策略应该可以提高一些性能。
===========================================================================

这个策略MM已经给你做了,不用用户程序额外操心了。用户策略再好也比不上MM和文件系统,因为它掌握着整个系统的情况。Akirya说的那种一次写操作是最起码的。Vista里面内存管理又做了很多进一步的优化,比如SuperFetch。MM还可以根据你的读写模式预测你下一个要读写的区域提前进行优化,等等。用映射文件可以自动得到这些好处。

以前有个比较著名的例子,就是在一台内存比较少的机器上运行Mac机的操作系统,速度还不如在同样的机器上用Virtual PC里面用大的虚拟内存运行Mac OS快。这个例子也说明Windows的Memory Manager性能是很优秀的。

题外话,Windows内存管理设计和实现都是一位华人杰出工程师(Distinguished Engineer),Landy Wang 做的。 (http://www.microsoft.com/presspass/exec/de/Wang/default.mspx)
esprite2000 2007-07-08
  • 打赏
  • 举报
回复
mark
康熙说编程 2007-07-08
  • 打赏
  • 举报
回复
举个不恰当的例子,你从国外进石油,ReadFile/WriteFile好比海关进货,一船一船来,装货卸货(复制到用户Buffer),还得检查入关。Image Mapping好比用石油管道。虽然最终都是从国外的油田(硬盘)上读文件,速度是不同的,差别不是在采油(读盘)那一块。
-----------------------------------------------------------------
这个比喻挺有意思。
DentistryDoctor 2007-07-08
  • 打赏
  • 举报
回复
基本的IO肯定是少不了。要提高IO速度,用一个好的缓存策略应该可以提高一些性能。
  • 打赏
  • 举报
回复
内存文件映射肯定是做缓存的.
假如做了一个4K的文件映射到内存,你写了1024次一次一个字节.然后关闭文件,这个时候用文件映射明显要快很多,很可能就执行了一次写的操作.
CathySun118 2007-07-08
  • 打赏
  • 举报
回复
mark
cczlp 2007-07-07
  • 打赏
  • 举报
回复
没测试过哪种方式快
拿节 2007-07-07
  • 打赏
  • 举报
回复
顶下!等会看!
feimingbiao 2007-07-07
  • 打赏
  • 举报
回复
我并不是杜撰人们的想法。比如根据我google发现,网上有人说“内存映射文件直接将文件的地址映射到进程的地址空间中,那么操作文件就相当于在内存中操作一样,省去了读和写I/O的时间;第二种方式(指文件IO API方式)是必须这么做(READFILE,WRITEFILE),这个过程是很慢的。”(http://www.xiaozhou.net/ReadNews.asp?NewsID=953)
==============================================================

这个说法是对的。内存映射是MemoryManager(mm)来处理的,机理和 MM 处理虚拟内存的PageFile是一模一样的,虽然也是读盘上的东西,但它是不走I/O的。否则Paging的速度太慢,系统性能太差,受不了。另外MemoryManager还可以利用文件系统的一些性能做Smart Caching,你常用的东西可以留在内存里面,读取就很快了。不知道你以前用没用过RamDisk,现在MM的性能比RamDisk还要好。

ReadFile/WriteFile就是不同机制了,他们走I/O Manager,一个Buffer一个Buffer的要,速度是很慢的,虽然Vista加大了Buffer(到了几兆),但是来回来去的费用还是太高。所以损耗不是在硬盘的读取上,而是在路上了。

举个不恰当的例子,你从国外进石油,ReadFile/WriteFile好比海关进货,一船一船来,装货卸货(复制到用户Buffer),还得检查入关。Image Mapping好比用石油管道。虽然最终都是从国外的油田(硬盘)上读文件,速度是不同的,差别不是在采油(读盘)那一块。

15,466

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧