关于内存页面保护的问题

这是我在阅读<Windows通过C / C ++第5版>时遇到的另一个问题。 首先,我们来看看一些报价。

LPVOID WINAPI VirtualAlloc( __in_opt LPVOID lpAddress, __in SIZE_T dwSize, __in DWORD fdwAllocationType, __in DWORD fdwProtect ); 

最后一个参数fdwProtect指示应分配给区域的保护属性。 与区域关联的保护属性对映射到区域的已提交存储没有影响。

保留区域时,将最常用的保护属性与提交给该区域的存储分配。 例如,如果您打算提交具有PAGE_READWRITE保护属性的物理存储,则应该使用PAGE_READWRITE保留该区域。 当区域的保护属性与提交的存储的保护属性相匹配时,系统的内部logging保持更有效。

(在提交存储时)…通常会传递在调用VirtualAlloc来保留区域时所使用的页面保护属性, 尽pipe您可以指定不同的保护属性。

上面的引文完全让我感到困惑。

  • 如果与区域相关的保护属性对已提交的存储没有影响,为什么我们需要它?

  • 由于build议在保留和提交时使用相同的保护属性,为什么Windows仍然提供使用不同属性的选项? 难道它不是领先的,而是一种悖论?

  • 分别为保留区域承诺存储保存的保护属性究竟在哪里?

非常感谢您的见解。

在上下文中阅读是很重要的。

与区域关联的保护属性对映射到区域的已提交存储没有影响。

指的是保留 ,而不是承诺区域。

一个保留的页面没有后备存储,所以它的保护总是在概念上PAGE_NOACCESS, 无论你传递给VirtualAlloc 。 即如果一个线程试图读取/写入保留区域中的地址,则会引发访问冲突。

从链接的文章:

保留的地址总是PAGE_NOACCESS,这是系统强制执行的默认值,不管传递给函数的值是多少。 提交的页面可以是只读,可读写或不可访问的。

回覆:

  • 分别为保留区域和已提交存储保存的保护属性究竟在哪里?

虚拟地址区域的保护属性存储在每个进程的VAD树中。 (VAD ==虚拟地址描述符,请参阅Windows内部或链接的文章)

由于建议在保留和提交时使用相同的保护属性,为什么Windows仍然提供使用不同属性的选项? 难道它不是领先的,而是一种悖论?

因为函数总是接受一个保护参数,但是它的行为依赖于fdwAllocationType 。 保护只对承诺的存储有意义。

Richter建议使用相同的保护设置的原因大概是因为区域中保护标志的更少变化意味着更少的“块”(请参阅​​您的书的定义),因此VAD的AVL树较小。 也就是说,如果一个地区的所有页面都提交了相同的标志,那么只会有一个区块。 否则,可能会有与该区域中页面一样多的块。 而且你需要每个块的VAD(而不是页面)。

阻止==具有相同保护/状态的连续页面组。

如果与区域相关的保护属性对已提交的存储没有影响,为什么我们需要它?

如上。

那么…一个原因可能是你可以使用保护页,所以你可以提交内存,因为你使用它。

想想Windows中的线程堆栈; 紧挨着堆栈的页面被设置为一个保护页面,通常具有读写能力。 一旦触发了守护页,异常处理程序就会运行并提交守护页,并使下一页成为守卫。

看到这里更好的描述。 另外,这个链接是关于Windows如何处理低级资源并且非常好的阅读的系列文章的一部分。

允许您重新指定保护属性的另一个原因可能是复制写入技术。 页面被设置为只读,直到它们被更改,这可以引发异常,你可以处理等等等等

在386系列英特尔芯片上,提交,读/写/保留标志存储在页表中。 请参阅386芯片参考了解更多详情。 编辑:我戳了一下,找不到MS存储PAGE_GUARD位。 现在我好奇我在哪里看到它。 :)太糟糕了,去年春天我扔了大约500磅的旧参考材料。

希望这可以帮助 :)