内存映射文件

 

1.概览

  (1) 什么时内存映射文件
       内存映射文件是由一个文件到一块内存的映射, 使进程虚拟地址空间的某个区域与磁盘上某个文件的部分或全部内容的建立映射。 建立映射后,通过该区域可以直接对被映射的磁盘文件进行访问. 而不必执行文件I/O 操作也无需对文件内容进行缓冲处理。 就好像整个被映射的文件都加载到了内存一样,因此内存文件映射非常适合于用来管理大文件。
       注:与虚拟内存使用的是Page file 不同, 内存映射使用的是磁盘上的用户指定的文件。
当创建一个线程时,
    1.系统只是保留了足够大的对应的.exe文件区域,将.exe文件本身作为物理内存,执行映射,却并未提交;
    2.访问.exe文件的部分区域,以确定依赖的.dll(这将导致部分页面被提交);
    3.依次LoadLirary(像为.exe保留区域一样,也为.dll保留区域,并有些类似第4步);
    4.执行.exe的启动代码,并持续执行(执行到哪就提交哪块).
  (2)3 种用途
     系统用内存映射文件加载和执行EXE,DLL 文件。既节省了Page file 的空间,又加快了程序的执行。
     用内存映射文件机制访问文件遮蔽了对文件I/O 操作和文件内容的缓存操作
     它是最有效的进程间通信机制,其它的进程间通信机制都是基于内存映射文件的。        

2.程序的组成

  同一个程序可能运行多个实例,而每个进程都把原始文件当作物理内存看待,那么其中一个进程修改了某部分数据或代码,其他进程是否也被改动了呢?答案是否定的。由于Copy-On-Write的干预,每当一个进程试图修改全局变量(或代码)时,都会把这个变量所在的页重新拷贝一份,并把虚拟地址映射到这个拷贝上,此时怎么改都只是改动单独为此进程准备的副本,而不会影响其他进程。
     每个DLL,EXE 文件都是由一些段组成( .data, .rdata, .text)
     段共有四个属性:读(R) 、写(W) 、执行(E) 、共享(S)
     建段:
         #pragma data_seg(" 段名")
         //data
         #pragma data_seg()
               例:#pragma data_seg("MY")
                   volatile LONG g_lApplicationInstances = 0;
                   #pragma data_seg()
                                                
     设置段属性:
          #pragma comment(linker, "/Section: 段名, 段属性")
                 例:#pragma comment(linker, "/Section:MY,RWS")
       默认情况下用户新建的段中只能存放初始化的数据,若数据未始化,该数据会被系统自动放到其它的段中,而不会放到用户指定的段。
     allocate 宏可以帮助我们在新建的段中放入未初始的数据,
                 : // Uninitialized, in Shared section
                     __declspec(allocate("MY")) int d;

3.内存映射文件的用法

     使用前:
     (1) 创建一个文件内核对象,指向磁盘上要做为内存映射的文件
     (2) 创建一个文件映射内核对象,并告诉系统文件的大小及如何访问这个文件( 读、写)            
     (3) 告诉系统把文件映射对象的部分和全部映射到进程的地址空间中。    
     使用后
      (1) 告诉系统从你的进程的地址空间中撤消文件映射内核对象的映像
      (2) 关闭文件映射内核对象
      (3) 关闭文件内核对象。        
HANDLE hFile = CreateFile( );
HANDLE hFileMapping = CreateFileMapping(hFile,  );
CloseHandle(hFile);
PVOID pvFile = MapViewOfFile(hFileMapping,  );
CloseHandle(hFileMapping);
// Use the memory-mapped file.
UnmapViewOfFile(pvFile);            

4.内存映射与一致性 

   1. 仅使用内存映射
     多个进程可以同时对一个文件进行映射。当其中一个进程修改文件的内容时,被修改的内容会同时反映到其它进程中。
     这是因为文件在内存中只有一份实例,进程只是对这块内存做了映射并没有创建副本。            
   2. 内存映射与WriteFile 操作
     若一个进程A 用内存映射对文件进行操作,另一个进程B 用文件操作函数WriteFile 对同一文件进行操作
     A 对文件的修改不会反应到B 中,反之亦然。因为内存映射永远也不要在网络文件中使用。
在本地可以通过独占打开文件避名文件操作的不一致性。
5.Common API:
              CreateFileMapping MapViewOfFile      OpenFileMapping
              UnmapViewOfFile FlushViewOfFile

你可能感兴趣的:(文件)