第十三章 Windows内存构架
1.进程虚拟地址空间
每个进程都有自已的私有的虚拟地址空间,在32位机器上是4G,在64位机器上是16EB。
进程内的线程只能访问其所属进程所占的内存,其它进程的内存对其而言是不可见的,无法访问到。
2.虚拟地址空间是如何划分的
以32位 x86进程的虚拟地址被分成四个区域(Partition)
(1)空指针区域
范围:0x00000000 ~ 0x0000FFFF
地址空间中的以上部分是专门留出来帮助程序员捕获空指针操作,如果线程试图读、写该区域所占的内存会导致进程异常退出。
(2)用户模式区域
范围:0x00010000 ~ 0x7FFEFFFF (共2G)
任何进程都不可读、写其它进程在该区域存放的数据。
所有的DLL和EXE文件都会加载到该区
通过控制BCD可以增加用户模式区哉的范围,详见:
http://www.microsoft.com/whdc/system/platform/firmware/bcd.mspx
(3)内核模式区域
范围:0x80000000 ~ 0xFFFFFFFF
操作系统的代码存放在这里,如线程、内存管理、文件系统支持、网络支持、设备驱动。
该区存放的所有东西被所有进程共享。
该区存放的代码和数据会被保护起来,应用程序若试图读、写该区的内存会导致异常退出,
除非应用程序的线程则用户模式切换到内核模式。
(4)64KB禁上入内区域
范围:0x7FFF0000 ~ 0x7FFFFFFF
3.地址空间内的区域
VirtualAlloc该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页。
根据CPU不同,VirtualAlloc分配的粒度也不同,但一般都是以64KB为基本单位。
不同CPU分页大小也不同,X86和X64分页大小是4K
(1)保留地址空间 Reserve address space
保留地址空间:在进程地址空间中保留出一块地址空间也备后用。因为这块地址空间并没有实际的存储映射,所以若访问这块内存会导致进程异常退出。
VOID GetSystemInfo(LPSYSTEM_INFO psi);取得系统分页大小、内存分配粒度(Allocation Granularity)
在保留地址空间时有两点限制:
1.被保留地址空间的首地址必须以内存分配粒度为边界(地址的值可以整除内存分配粒度的值)
2.被保留地址空间的大小必须是页大小的整数倍,若不是整数倍系统会自动对齐到整数倍。
例如,页大小为4K,若要保留10KB大小的空间,系统会自动对齐,保留12K(4*3)大小的空间
(2)提交物理存储到保留的地址空间
物理存储包括:物理内存和用做虚拟内存的页文件。
物理存储总是以分页大小为基本单位提交的
4.物理内存和页文件
物理内存(RAM):内存硬件的实际存储容量
虚拟内存:用于当做内存来弥补计算机RAM空间缺乏的硬盘空间。当实际RAM满时(实际上,在RAM满之前),虚拟内存就在硬盘上创建了。
当物理内存用完后,虚拟内存管理器选择最近没有用过的,低优先级的内存部分写到交换文件上。
这个过程对应用是隐藏的,应用程序把虚拟内存和实际内存看作是一样的。虚拟内存大小是由系统的页文件(Paging file)限制的。
5.数据对齐
如果一个变量的地址可以整除该变量所占内存大小,那么就称该变量是数据对齐的。
如DWORD的大小是4 若其地址为0x00000004 那么它就是数据对齐的。
7.Copy-On-Write
一个应用程序的多个实例在运行时共享代码段或数据段。但某个实例修改全局或静态变量时,系统会以Copy-on-write的方式修改全局变量。
即,系统会新建一个页,然后所要修改的全局变量所在的页的内容拷贝到新的页上,再在新的页上修改全局变量。
8.系统信息
用虚拟内存编程时需要用到一些系统的一些信息,如分页大小,分配粒度大小等等。
为了避免将这此信息Hard Code到代码中,使程序具有更好的移植性,我们可能通过调用下面的方法获取我们需要的信息。
VOID GetSystemInfo(LPSYSTEM_INFO psi);
9.Common API
VirtualAlloc VirtualFree
VirtualQuery