0%

Windows核心编程 - Windows内存结构

最近在学习 Win32编程,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习Win32开发的童鞋们提供一份参考。

本系列博文均根据学习《Windows核心编程》一书总结而来;

运行环境:

  • 操作系统: Windows 10家庭版
  • 编译器:Visual Studio 2019

Windows内存结构

进程的虚拟地址空间

每个进程都被赋予自己的虚拟地址空间。对于32位进程来说,这个地址空间是4GB,因为32位指针可以拥有从0x00000000~0xFFFFFFFF之间的任意一个值。由于每个进程都可以接受它自己的私有地址空间,因此当进程中的一个线程在运行时,该进程只能访问它自己的进程内存。其他所有进程的内存则隐藏。

虚拟地址空间并标识真正的物理地址空间,虚拟地址只是微软开的空头支票;

虚拟地址分区

每个进程的虚拟地址空间都要划分成为各个分区。

NULL指针分配分区

进程地址空间的这个分区的设置是为了帮助程序员掌握 N U L L指针的分配情况。如果你的进程中的线程试图读取该分区的地址空间的数据,或者将数据写入该分区的地址空间,那么C P U就会引发一个访问违规。

1
2
int* pnSomeInteger = (int *)malloc(sizeof(int));
*pnSomeInteger = 5;

MS-DOS兼容分区

进程地址的4MB分区是Windows为了维护16位程序与32位程序之间的兼容性而设置的;

用户方式分区

这个分区是进程的私有(非共享)地址空间所在的地方。一个进程不能读取、写入、或者以任何方式访问驻留在该分区中的另一个进程的数据。对于所有应用程序来说,该分区是维护进程的大部分数据的地方。

Windows操作系统将4GB内存分为两块,用户区和内核区,低2gb是用户区,高2gb是内核区

64KB禁入区

个位于用户方式分区上面的64 KB分区是禁止进入的,访问该分区中的内存的任何企图均将导致访问违规。 M i c r o s o f t之所以保留该分区,是因为这样做将使得M i c r o s o f t能够更加容易地实现操作系统。当将内存块的地址和它的长度传递给Wi n d o w s函数时,该函数将在执行它的操作之前使内存块生效。

在用户区中,使用WriteMemory等函数对它进行写入,一定会导致访问违规

内核方式分区

这个分区是存放操作系统代码的地方。用于线程调度、内存管理、文件系统支持、网络支持和所有设备驱动程序的代码全部在这个分区加载。驻留在这个分区中的一切均可被所有进程共享。

地址空间中的区域

当进程被创建并且赋予它的地址空间时,该可用地址空间的主体是空闲的,即未分配;

每当你保留地址空间的一个区域时,系统要确保该区域从一个分配粒度的边界开始。X86平台使用64KB这个相同的分配粒度

当你保留地址空间的一个区域时,系统还要确保该区域的大小是系统的页面大小的倍数。页面是系统在管理内存时使用的一个内存单位。与分配粒度一样,不同的 C P U,其页面大小也是不同的。 x 8 6使用的页面大小是4 KB,

提交地址空间区域中的物理存储器

若要使用已保留的地址空间区域,必须分配物理存储器,然后将该物理存储器映射到已保留的地址空间区域。这个过程成为提交物理存储器。物理存储器总是以页面的方式提交的。

物理存储器与页文件

页文件透明的增加了应用程序可以使用的RAM的数量。

当硬盘上的一个程序的文件映像(这是个 . e x e文件或D L L文件)用作地址空间的区域的物理存储器时,它称为内存映射文件。当一个 . e x e文件或D L L文件被加载时,系统将自动保留一个地址空间的区域,并将该文件映像映射到该区域中。

保护属性

已经分配的物理存储器的各个页面可以被赋予不同的保护属性。

Copy On Write

操作系统为共享内存块赋予了Copy-On-Write保护属性。当一个dll或exe模块被映射到一个内存地址的时候,系统将计算有多少页面是额可以写入的。

当一个进程中的线程试图将数据写入一个共享内存块的时候,系统就会进行干预,并执行以下操作:

  • 系统查找RAM中的一个空闲页面。
  • 系统将试图被修改的页面内容拷贝到第一步找到的页面中;
  • 系统更新进程的页面表,使得被访问的虚拟地址被转换成新的RAM页面

综合使用所有元素