内存保护

属于进程的内存受其专用虚拟地址空间隐式保护。 此外,Windows 使用虚拟内存硬件提供内存保护。 此保护的实现因处理器而异,例如,进程的地址空间中的代码页可以标记为只读,并防止用户模式线程修改。

有关属性的完整列表,请参阅 内存保护常量

写入时复制保护

写入时复制保护是一种优化,允许多个进程映射其虚拟地址空间,以便它们共享物理页,直到其中一个进程修改页面。 这是称为 惰性评估的技术的一部分,它允许系统通过在绝对必要之前不执行操作来节省物理内存和时间。

例如,假设两个进程将同一 DLL 中的页面加载到其虚拟内存空间中。 这些虚拟内存页映射到这两个进程的相同物理内存页。 只要两个进程都不写入这些页面,它们就可以映射到并共享相同的物理页面,如下图所示。

映射到相同物理内存的进程 1 和 2 页的框和箭头

如果进程 1 写入其中一个页面,则物理页的内容将复制到另一个物理页,并为进程 1 更新虚拟内存映射。 现在,这两个进程在物理内存中都有自己的页面实例。 因此,一个进程不可能写入共享物理页,另一个进程无法查看更改。

进程和物理内存重新映射的框和箭头

加载应用程序和 DLL

当加载同一个基于 Windows 的应用程序的多个实例时,每个实例在其自己的受保护虚拟地址空间中运行。 但是,它们的实例处理 (hInstance) 通常具有相同的值。 此值表示应用程序的虚拟地址空间中的基址。 如果每个实例都可以加载到其默认基址中,则它可以使用写入时复制保护映射到其他实例并与其他实例共享相同的物理页。 系统允许这些实例共享相同的物理页,直到其中一个实例修改页面。 如果出于某种原因无法将其中一个实例加载到所需的基址中,它将接收自己的物理页。

DLL 是使用默认基址创建的。 每个使用 DLL 的进程都将尝试在 DLL 的默认虚拟地址处的自己的地址空间中加载 DLL。 如果多个应用程序可以在 DLL 的默认虚拟地址处加载 DLL,则可以共享 DLL 的相同物理页。 如果出于某种原因,进程无法在默认地址加载 DLL,它会在其他位置加载 DLL。 写入时复制保护强制将某些 DLL 页面复制到此过程的不同物理页中,因为跳转指令的修补程序是在 DLL 的页面中编写的,并且对于此过程,它们将有所不同。 如果代码部分包含对数据节的多个引用,这可能会导致整个代码节复制到新的物理页。