当前位置:   article > 正文

Windows核心编程—第17章—内存映射文件

Windows核心编程—第17章—内存映射文件

虚拟内存一样,内存映射文件可以用来保留一个地址空间的区域,并将物理存储器提交给该区域。它们之间的差别是,物理存储器来自一个已经位于磁盘上的文件,而不是系统的页文件。一旦该文件被映射,就可以访问它,就像整个文件已经加载到内存一样。
内存映射文件场景

  1. 系统使用内存映射文件,以便加载和执行exe和dll文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。
  2. 可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O 操作,并且可以不必对文件内容进行缓存。
  3. 可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。

当线程调用CreateProcess时,系统将执行下列操作步骤:

  1. 系统找出在调用CreateProcess时设定的exe文件。如果找不到这个exe文件,进程将无法创建,CreateProcess将返回false。
  2. 系统创建一个新进程内核对象。
  3. 系统为这个新进程创建一个私有地址空间。
  4. 系统保留一个足够大的地址空间区域,用于存放该exe文件
  5. 系统注意到支持已保留区域的物理存储器是在磁盘上的exe文件中,而不是在系统的页文件中。当exe文件被映射到进程的地址空间中之后,系统将访问exe文件的一个部分,该部分列出了包含exe文件中的代码要调用的函数的dll文件。然后,系统为每个dll文件调用LoadLibrary函数,每当调用LoadLibrary来加载一个dll时,系统将执行类似上面的第4和第5个步骤。
  6. 当所有的exe和dll文件都被映射到进程的地址空间之后,系统就可以开始执行exe文件的启动代码。当进程中的线程每次试图访问尚未加载到内存的代码或数据时,那么就会出现一个错误。系统能够发现这个错误,并且自动将这页代码从该文件的映像加载到一个内存页面。然后,系统将这个内存页面映射到进程的地址空间中的相应位置,接着让线程继续运行。

引入内存映射文件
目的:逆序一个文件的内容
方法1:一个文件,一个缓存,从文件一次性读到缓存,逆序后写回去,缺点1:无法处理大文件,缺点2:如果写回时过程异常,文件被破坏
方法2:两个文件,一个缓存,读一定大小文件内容到缓存,逆序后写入新文件,不断反复。缺点1:速度慢,缺点2:需要两个文件所占的磁盘空间
方法3:一个文件,一个缓存,读一定大小文件内容到缓存,逆序后写回去 ,缺点:如果写回时过程异常,文件被破坏
方法4:一个文件,零缓存,使用内存映射,无需分配/释放内存和加载/写回文件数据到内存:缺点:过程异常,文件被破坏

如何使用内存映射
1 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件。
2 创建一个文件映射内核对象,告诉系统该文件的大小和你打算如何访问该文件。
3 让系统将文件映射对象的全部或一部分映射到你的进程地址空间中。

auto fileHandle = CreateFile("./123.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, nullptr);
if (fileHandle == INVALID_HANDLE_VALUE) {
	return 0;
}
auto mapHandle = CreateFileMapping(fileHandle, nullptr, PAGE_READWRITE, 0, 100, nullptr);
if (mapHandle == nullptr) {
	return 0;
}
auto pointer = MapViewOfFile(mapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

用完后
1 告诉系统从你的进程的地址空间中撤消文件映射内核对象的映像。
2 关闭文件映射内核对象。
3 关闭文件内核对象。

UnmapViewOfFile(pointer);
CloseHandle(mapHandle);
CloseHandle(fileHandle);
  • 1
  • 2
  • 3

如果需要确保你的更新被写入磁盘,可以强制系统将修改过的数据的一部分或全部重新写入磁盘映像中,方法是调用FlushViewOfFile函数。对于存储器是在网络上的内存映射文件来说, FlushViewOfFile能够保证文件的数据已经从工作站写入存储器。但是FlushViewOfFile不能保证正在共享文件的服务器已经将数据写入远程磁盘,因为服务器也许对文件的数据进行了高速缓存。若要保证服务器写入文件的数据,每当你为文件创建一个文件映射对象并且映射该文件映射对象的视图时,应该将FILE_FLAG_WRITE_THROUGH标志传递给CreateFile函数。如果你使用该标志打开该文件,那么只有当文件的全部数据已经存放在服务器的磁盘驱动器中的时候, FlushViewOfFile函数才返回。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/888917
推荐阅读
相关标签
  

闽ICP备14008679号