【问题标题】:Clarification on how virtual memory manager in Windows fetches memory mapped file data关于 Windows 中的虚拟内存管理器如何获取内存映射文件数据的说明
【发布时间】:2017-12-24 07:30:56
【问题描述】:

比如说,如果我有一个大文件映射到我的进程的虚拟地址空间中:

//Error handling is omitted for brevity
HANDLE hFile = CreateFile(L"path-to\\file", 
            GENERIC_READ,
            FILE_SHARE_READ, NULL, OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
char* pAddress = (char*)MapViewOfFile(hFileMapping,
            FILE_MAP_READ, 0, 0, 0);

//And get the data
char data_byte = pAddress[offset];

//Then remember to do the cleanup ....

内核虚拟内存管理器何时从磁盘上的文件中读取实际数据(或执行 I/O 操作以从硬盘驱动器获取数据):

A) 当MapViewOfFile 被调用时,或者

B) 当我使用pAddress[offset]访问它时?

如果上面的答案是 B,还有第二个问题——当它获取数据时:

C) 它是否读取整个文件,或者

D) 仅包含页面(4K 大小左右)?

【问题讨论】:

  • 答案 - B 和 D

标签: c winapi window


【解决方案1】:

BD

当您调用MapViewOfFile (ZwMapViewOfSection) 时,内核保留虚拟视图范围但不将其与实际物理页面相关联(因此不要在开始时分配物理页面)。当您第一次访问部分视图中的某个地址时 - 因为它尚未与物理页面关联(PTE 无效) - cpu 将生成异常。当系统处理这个异常时,它分配已经物理页面,将虚拟地址与这个页面相关联,从文件中读取数据到它(如果部分由文件支持)并继续从指令执行,这会产生异常。

所以系统不仅在您将文件映射到内存时从文件中读取数据,而且还要等到您第一次访问它。并且在第一次访问时 - 它读取的数据不是整个部分范围(部分可以不是从文件开始,也不能在文件结尾结束),但只访问页面(可能是几页)

【讨论】:

  • ETHREAD 结构有几个值可能会影响在处理页面错误时作为集群读入的页面数量:DisablePageFaultClustering(默认为 false)和ReadClusterSize(默认是 7)。它似乎按预期工作。我将线程的ReadClusterSize 降低到 3,并让它访问映射的数据文件。在本地内核调试器中,我可以看到加载两个连续页面后,接下来的 ReadClusterSize - 1 页面已经有效。
猜你喜欢
  • 2015-09-01
  • 2013-10-25
  • 1970-01-01
  • 2011-01-08
  • 2011-12-31
  • 2021-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多