为什么 Windows 推迟为数据文件创建 PPTE?
Why does Windows defer creation of PPTEs for data files?
FSD 在 reading/writing 时第一次调用 CcInitializeCacheMap
到文件,这将导致创建私有缓存映射、节对象、控制区域、段、子节(如果它们不存在) '已经存在。当缓存管理器创建一个部分对象时,它将在 NtCreateSection
的 sectionattributes 参数中指定它是一个数据部分 SEC_DATA,这意味着 PPTE 最初未配置并且段中的基数留空。实际读取是使用 CcCopyRead
完成的,它将首先分配 VACB 并映射文件视图,然后从 VACB 复制到缓冲区。每次它分配一个 VACB 时,它都会将一个 265kb 的视图映射到缓存管理器虚拟 space。当它进行此映射时,它需要初始化一个 PPTE,但是当它初始化一个 PPTE 时,它还不如为整个文件初始化所有的 PPTE,因为它们在设计上需要是连续的;该内存将被保留,无论它们是否被分配。
Windows 内部人员声称它推迟为数据文件创建 PPTE,直到第一个视图被映射,但是对于图像文件,它在创建部分对象时创建它们。
For page-file-backed sections, an array of prototype PTEs is created when a section object is first created. For mapped files, portions of the array are created on demand as each view is mapped.
另一个来源指出:
While mapping a data file, the main purpose of MiCreateDataFileMap is to setup the subsection object. In the normal case only one subsection is created, but under some special conditions multiple subsections are used, e.g. if the file is very large. For data files, the subsection field SubsectionBase is left blank. This defers the creation of PPTE until the the section is mapped into the memory and finally accessed for the first time. The reasoning behind this is to avoid wasting memory when very large data files are mapped. Instead the SegmentPteTemplate field of the segment object is setup properly which can be used to create the PPTEs subsequently if necessary.
我不同意这一点,因为如果映射一个 4GB 的数据文件,它只需要 2MB 的 PPTE 页面,这不是很多 space,所以我看不到这样做的好处.真正的 space 节省来自 VACB 以及整个文件不必驻留在物理内存中这一事实。
为什么他们声称 'portions' 的 PPTE 是按需初始化的,就好像它在暗示它正在节省 space 一样,这仍然没有意义,因为它只是没有,因为一旦一个 PPTE 是mapped 整个区域被保留,并且SubsectionBase
在段中设置,因为整个文件的PPTE需要是连续的。
'portions' 可以按需初始化,但它不会改变 space 被保留的事实,无论那里是否有 PPTE。例如,当分配 VACB 时,它可以初始化覆盖 256kb 的所有 PPTE。当页面错误发生时,PTE 指向 PPTE,PPTE 将无效,因此它可以在 256kb 粒度上执行 256kb 集群 IO,这意味着任何其他页面错误都将是软页面错误。 (我相信当第一次分配 PPTE 时,在为 VACB 视图分配 PTE 时,PTE 被指向 PPTE。Windows 内部人员提出了一些关于用于搜索的错误虚拟地址的胡说八道PPTE 进程的 VAD 在第 411 页开始和结束,但系统缓存是内核内存的一部分,VAD 不会跟踪它,所以这是错误的。此方法仅用于用户 space 映射)。一个问题是页面可能会被修改,因此它不一定能进行 256kb 集群优化(1 个硬页面错误,63 个软页面错误)并将页面锁定到内存中以执行 IO。它必须知道所有的 PPTE 都是新分配的,并且故障不仅仅是因为不存在单个帧。最好的办法是在映射范围内的视图并分配 PPTE 时执行 IO,这样在读取时不会发生页面错误。否则它将不得不处理 64 个硬页面错误。
那有什么意义呢?它也可以在创建数据文件部分后立即初始化 PPTE 数组,因为它只会在上面的场景中立即被读取。我想不出一个进程会将大量文件映射到它的地址 space 然后不碰它们的场景。即使它映射了 40GB,它在创建数据部分时初始化的 PPTE 中仍然只占用 20MB。
我认为好处来自这样一个事实,即保留的包含 PPTE 的虚拟范围实际上并未映射到物理内存,尽管虚拟 space 中的整个 PPTE 范围都将被占用为每个过程。当一个 VACB 被映射时,该范围的 PPTE 部分将被填充,现在在物理内存中有成本。然而,对于一个 40GB 的文件来说,它仍然只有 20MB。 20MB 将在虚拟内存中保留,但在物理内存中为 0。每个 256KB 视图占用的物理量 space 将增加 64*8 字节。
FSD 在 reading/writing 时第一次调用 CcInitializeCacheMap
到文件,这将导致创建私有缓存映射、节对象、控制区域、段、子节(如果它们不存在) '已经存在。当缓存管理器创建一个部分对象时,它将在 NtCreateSection
的 sectionattributes 参数中指定它是一个数据部分 SEC_DATA,这意味着 PPTE 最初未配置并且段中的基数留空。实际读取是使用 CcCopyRead
完成的,它将首先分配 VACB 并映射文件视图,然后从 VACB 复制到缓冲区。每次它分配一个 VACB 时,它都会将一个 265kb 的视图映射到缓存管理器虚拟 space。当它进行此映射时,它需要初始化一个 PPTE,但是当它初始化一个 PPTE 时,它还不如为整个文件初始化所有的 PPTE,因为它们在设计上需要是连续的;该内存将被保留,无论它们是否被分配。
Windows 内部人员声称它推迟为数据文件创建 PPTE,直到第一个视图被映射,但是对于图像文件,它在创建部分对象时创建它们。
For page-file-backed sections, an array of prototype PTEs is created when a section object is first created. For mapped files, portions of the array are created on demand as each view is mapped.
另一个来源指出:
While mapping a data file, the main purpose of MiCreateDataFileMap is to setup the subsection object. In the normal case only one subsection is created, but under some special conditions multiple subsections are used, e.g. if the file is very large. For data files, the subsection field SubsectionBase is left blank. This defers the creation of PPTE until the the section is mapped into the memory and finally accessed for the first time. The reasoning behind this is to avoid wasting memory when very large data files are mapped. Instead the SegmentPteTemplate field of the segment object is setup properly which can be used to create the PPTEs subsequently if necessary.
我不同意这一点,因为如果映射一个 4GB 的数据文件,它只需要 2MB 的 PPTE 页面,这不是很多 space,所以我看不到这样做的好处.真正的 space 节省来自 VACB 以及整个文件不必驻留在物理内存中这一事实。
为什么他们声称 'portions' 的 PPTE 是按需初始化的,就好像它在暗示它正在节省 space 一样,这仍然没有意义,因为它只是没有,因为一旦一个 PPTE 是mapped 整个区域被保留,并且SubsectionBase
在段中设置,因为整个文件的PPTE需要是连续的。
'portions' 可以按需初始化,但它不会改变 space 被保留的事实,无论那里是否有 PPTE。例如,当分配 VACB 时,它可以初始化覆盖 256kb 的所有 PPTE。当页面错误发生时,PTE 指向 PPTE,PPTE 将无效,因此它可以在 256kb 粒度上执行 256kb 集群 IO,这意味着任何其他页面错误都将是软页面错误。 (我相信当第一次分配 PPTE 时,在为 VACB 视图分配 PTE 时,PTE 被指向 PPTE。Windows 内部人员提出了一些关于用于搜索的错误虚拟地址的胡说八道PPTE 进程的 VAD 在第 411 页开始和结束,但系统缓存是内核内存的一部分,VAD 不会跟踪它,所以这是错误的。此方法仅用于用户 space 映射)。一个问题是页面可能会被修改,因此它不一定能进行 256kb 集群优化(1 个硬页面错误,63 个软页面错误)并将页面锁定到内存中以执行 IO。它必须知道所有的 PPTE 都是新分配的,并且故障不仅仅是因为不存在单个帧。最好的办法是在映射范围内的视图并分配 PPTE 时执行 IO,这样在读取时不会发生页面错误。否则它将不得不处理 64 个硬页面错误。
那有什么意义呢?它也可以在创建数据文件部分后立即初始化 PPTE 数组,因为它只会在上面的场景中立即被读取。我想不出一个进程会将大量文件映射到它的地址 space 然后不碰它们的场景。即使它映射了 40GB,它在创建数据部分时初始化的 PPTE 中仍然只占用 20MB。
我认为好处来自这样一个事实,即保留的包含 PPTE 的虚拟范围实际上并未映射到物理内存,尽管虚拟 space 中的整个 PPTE 范围都将被占用为每个过程。当一个 VACB 被映射时,该范围的 PPTE 部分将被填充,现在在物理内存中有成本。然而,对于一个 40GB 的文件来说,它仍然只有 20MB。 20MB 将在虚拟内存中保留,但在物理内存中为 0。每个 256KB 视图占用的物理量 space 将增加 64*8 字节。