【WIN32进阶之路】:内存映射文件
第一章:源起
遇到一个问题,如果一个客户数据文件有2g大,客户要通过界面查询文件中的数据并用列表控件显示数据,要怎么处理这个文件才能让应用程序不会长时间无响应,客户感觉不到程序的卡顿?
第二章:解决之道
第一反应是用内存映射文件处理大文件,将文件分成数次映射至内存地址空间,避免一次性缓冲整个文件带来的界面长时间无响应,并将暂时不用的内存映射文件取消映射,客户是用列表控件进行显示,那就可以在首次加载的时候只加载第一页的内容就进行显示,之后在缓冲下一页的内容,当用户查看中间页面的内容时可以缓冲将当前页面的上下页面和首页、最后页面对应的文件加载至进程地址空间中,其他的文件映射视图取消映射。
进一步完善创建多线程处理,主线程创建文件映射内核对象,多个子线程分别映射磁盘文件的一部分至进程地址空间并进行数据分析,处理完数据的线程通过SendMessage或者PostMessage又或者锁、关键段、内核线程同步方式等通知界面线程,而界面线程再做一些NOT WAIT操作,添加两个进度条提示首页加载进度和整体文件加载进度,首页加载完成时隐藏进度条并显示数据。
第三章:正文
3A:内存映射文件介绍:
创建内存映射文件相当于先调拨一块地址空间区域,然后给区域调拨物理存储器。不同之处在于内存映射文件的物理存储器来自于磁盘上的文件,而不是从系统的页交换文件中分配的。
3B:内存映射文件主要用于以下三种情况:
1.系统使用内存映射文件来载入并运行.exe和动态链接库(.dll)文件,可以节省页交换文件的空间和应用程序启动的时间。
2.开发人员可以用内存映射文件来访问磁盘上的数据文件,使得我们可以避免直接对文件进行IO操作和对文件内容进行缓存。
3.通过内存映射文件,我们可以在同一台机器的不同进程之间共享数据,windows也提供了其他一些方式来在进程间传送数据,但这些方法都是通过内存映射文件包装而成,因此最快的同一台机器上的进程间共享数据方法就是内存映射文件。
3C:常用API
CreateFile:打开文件内核对象
CreateFileMapping:创建一个指定名称的文件映射内核对象,通过参数指定映射到进程地址空间的文件句柄。
OpenFileMapping:打开一个指定名称的文件映射内核对象。
MapViewOfFile:把文件数据映射到进程地址空间,通过参数指定映射到进程地址空间的文件映射句柄和文件访问方式。
FlushViewOfFile:处于速度上的考虑,系统会对文件数据的页面进行缓存处理,这样在处理文件映射视图时就不需要随时更新磁盘上的文件,调用FlushViewOfFile将文件映象的修改立即从高速缓存写入磁盘映象。
对内存映射文件的处理类似读取到内存中的文件,或者理解成操作一串字符串。
UnMapViewOfFile:完成文件数据映象的释放。
CloseHandle,关闭文件映射内核对象,关闭文件内核对象,要调用两次。
3D:注意事项:
可以对同一个文件创建多个内存映射文件,但系统并不保证多个内存映射文件之间的数据一致性,系统只保证同一个内存映射文件的多个视图数据一致。
用作内存映射文件的磁盘文件最好是只读属性,可以避免其他进程对文件修改二造成的映射文件和磁盘文件的不一致,如果无法确认文件是只读的,那么在创建文件对象的CreateFile时指定访问权限为独占。
不应该用内存映射文件来跨网络共享可写文件,系统无法知晓网络上另外一台电脑对文件的操作而继续使用内存中的原始数据。
内存映射文件不一定需要磁盘文件,也可以创建以页交换文件为后备存储器的内存映射文件。与创建以磁盘文件为物理存储器的内存映射文件不同的步骤是:不需CreateFile步骤,在CreateFileMapping时文件内核对象传参INVALID_HANDLE_VALUE,这就告诉系统物理存储设备从页交换文件分配而不是磁盘文件。
第四章:补充话题:
4A:稀疏调拨的内存映射文件
之前的内存映射文件要么从磁盘上的数据文件中调拨,要么从页交换文件中调拨,这意味着对存储器的使用可能并不如我们希望的那么高效。按照jeffrey大神的例子,有一个电子表格文件定义:
CELLDATA CellData[200][256];如果CELLDATA的大小是128字节,那么这个数组就需要6553600字节的物理存储器,这也就表示程序开始运行就需要从页交换文件中分配大量的物理存储器,但是用户通常只用前面几个单元格存放信息,绝大多数的单元格都是浪费的。
我们希望把电子表格作为文件映射对象来共享,但又不想一开始就分配这么大的物理存储器,但是采用文件分片映射视图的方式编程会很繁琐,此时我们可以采用稀疏文件映射方式。
稀疏调拨的内存映射文件方法:
CreateFileMapping的fdwProtect参数中指定SEC_RESERVE或SEC_COMMIT,这两个标记只有在以页交换文件为后备存储器来创建文件映射对象时才有意义,SEC_COMMIT标志让CreateFileMapping从页交换文件中调拨存储器。
如果在调用CreateFileMapping的时候传入SEC_RESERVE标志,那么系统不会从页交换文件中调拨屋里存储器,它只返回文件映射对象的句柄。
MapViewOfFile给指定的文件映射对象创建一个视图,即预定一块地址空间区域,但不会给该区域调拨任何物理存储器,此时访问该区域的操作都是非法的。
调用VirtualAlloc给共享区域调拨物理存储器,我们可以只调拨部分存储器给MapViewOfFile预定的地址空间区域,调拨物理存储器后所有映射了同一个文件映射对象的的视图的其他进程就可以成功的访问已调拨的页面。
PS:稀疏调拨的内存映射文件尚未实例验证过,诸君谨慎参考。
【WIN32进阶之路】:内存映射文件的更多相关文章
- 内存映射文件详解-----C++实现
先不说内存映射文件是什么.贴个代码先,. #include <iostream> #include <fcntl.h> #include <io.h> #inclu ...
- MemoryMappedFile 内存映射文件 msdn
http://msdn.microsoft.com/zh-cn/library/dd997372%28v=vs.110%29.aspx 内存映射文件 .NET Framework 4.5 其他版本 1 ...
- C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转
原文:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing ...
- C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped
节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作 ...
- .NET 4.0中使用内存映射文件实现进程通讯
操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段.Win32 API中也包含有创建内存映射文件的函数,然而,这些函数都 ...
- C++中使用内存映射文件处理大文件
引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...
- JAVA NIO之浅谈内存映射文件原理与DirectMemory
JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...
- C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案
C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...
- 【VS开发】内存映射文件3
内存映射文件 内存映射文件,是由一个文件到一块内存的映射.Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping).内存映射文件与虚拟内存有些类似,通过内存映射文 ...
随机推荐
- fd_set 用法
http://www.cnblogs.com/wolflion/archive/2011/07/13/2539137.html select()函数主要是建立在fd_set类型的基础上的.fd_set ...
- easyui datagrid 多表头设置
最近在做二维报表,要求报表的表头自定义.在网上找了好久二维报表的插件,一直找不到合适的.后来就用easyui 中的datagrid替代了一下. 根据实际需求,统计的信息可能不是一个模块中的字段信息,所 ...
- 深入理解Java虚拟机 - 虚拟机内存划分
在内存管理方面,Java相对于C和C++的区别在于Java具有内存动态分配以及垃圾收集技术,但平时我们很少去关注JVM的内存结构以及GC,在出现内存泄露或溢出方面的问题,排查工作将变得异常艰难. ...
- poj12月其他题解(未完)
最近编程的时间比较少啊…… poj3253 就是个合并果子,各种优先队列即可(显然单调队列最优) poj3263 线段树统计每个点被覆盖了多少次即可,注意要去重 poj3625 最小生成树 poj36 ...
- HNOI2008玩具装箱 (斜率优化)
总算A了,心情好激动…… 如果会了一类斜率优化,基本上这类题就成了套模版了…… 只是k函数不同 var n,l,x,tail,head,m:int64; i,j:longint; dp,q,s:..] ...
- Socket编程(九)
此为网络编程的一个系列,后续会把内容补上.....
- Java [leetcode 22]Generate Parentheses
题目描述: Given n pairs of parentheses, write a function to generate all combinations of well-formed par ...
- 如何创建,增加swap
使用分区做为SWAP比较好,速度比文件的快,也不容易产生磁盘碎片所有应该尽量使用分区作为SWAP. 先说说使用文件做为SWAP吧:一.因为做为SWAP的文件,必须是连续的,所以需要使用dd命令创建:[ ...
- undo日志
InnoDB’s Undo 前言 Undo log是InnoDB MVCC事务特性的重要组成部分.当我们对记录做了变更操作时就会产生undo记录,Undo记录默认被记录到系统表空间(ibdata)中, ...
- 8、四大组件之三-ContentProvider
课程目标: 理解ContentProvider的作用及好处 认清ContentProvider与数据存储的关系 掌握ContentProvider对外提供的数据模型形式 能够编写ContentReso ...