1.1. 物理地址
在物理存储器上的内存地址,一般由内核管理,应用程序无法直接得到。
1.2. 虚拟地址
在进程私有空间中的地址,即应用程序指针所指向的地址值。
1.3. 寻址空间
进程所能够范围的地址空间范围,跟指针的位数有关,指针的位数取决于cpu字长,32位指针的地址空间范围为4GB,64位指针的地址空间范围为1 6 E B。
2. windows内存结构
2.1. 虚拟地址空间的管理
对于32位多任务的windows操作系统来说,每个进程都在自己的私有地址空间(虚拟地址空间)运行,因此当进程中的一个线程正在运行时,该线程可以访问只属于它的进程的内存。属于所有其他进程的内存则隐藏着,并且不能被正在运行的线程访问。
在win2k中,属于内核的内存也是隐藏的,正在运行的线程无法访问。这意味着线程不能直接访问内核的数据。如果要想访问内核数据,则必须通过系统调用(系统win32 api)来操作,否则会引发一个内存错误异常。
Win98中,属于操作系统的内存是不隐藏的,正在运行的线程可以访问。因此,正在运行的线程常常可以访问操作系统的数据,也可以破坏操作系统(从而有可能导致操作系统崩溃)。
在Win98中,一个进程的线程不可能访问属于另一个进程的内存,与win2k相同。
建议无论在win98还是win2k中,都采用系统调用来访问内核(操作系统内存)。
2.2. 虚拟地址空间的划分
虽然32位的应用程序理论上可以访问4GB的地址空间,但是真正可以使用的地址空间并没有那么多。
每个进程的虚拟地址空间都要划分成各个分区。地址空间的分区是根据操作系统的基本实现方法来进行的。不同的Windows内核,其分区也略有不同。winxp的内存结构与win2k相同。
进程的地址空间分区表
分区 |
32位Windows 2000(x86和Alpha处理器) |
32位Windows 2000(x86w/3GB用户方式) |
64位Windows 2000(Alpha和IA-64处理器) |
Windows 98 |
N U L L指针分配的分区 |
0 x 0 0 0 0 0 0 0 0 0 x 0 0 0 0 F F F F |
0 x 0 0 0 0 0 0 0 0 0 x 0 0 0 0 F F F F |
0x00000000 00000000 0x00000000 0000FFFF |
0 x 0 0 0 0 0 0 0 0 0 x 0 0 0 0 0 F F F |
DOS/16位Windows应用程序兼容分区 |
无 |
无 |
无 |
0 x 0 0 0 0 0 1 0 0 0 0 x 0 0 3 F F F F F |
用户方式 |
0 x 0 0 0 1 0 0 0 0 0 x 7 F F E F F F F |
0 x 0 0 0 1 0 0 0 0 0 x B F F E F F F F F |
0x00000000 00010000 0x000003FF FFFEFFFF |
0 x 0 0 4 0 0 0 0 0 0 x 7 F F F F F F F |
64-KB |
0 x 7 F F F 0 0 0 0 |
0 x B F F F 0 0 0 0 |
0 x 0 0 0 0 0 3 F F F F F F 0 0 0 0 |
无 |
禁止进入 |
0 x 7 F F F F F F F |
0 x B F F F F F F F |
0 x 0 0 0 0 0 3 F F F F F F F F F F |
无 |
共享的MMF分区 |
无 |
无 |
无 |
0 x 8 0 0 0 0 0 0 0 |
文件(MMF)内核方式 |
0 x 8 0 0 0 0 0 0 0 0 0 x F F F F F F F F |
0 x C 0 0 0 0 0 0 0 0 x F F F F F F F F |
0x00000400 00000000 0xFFFFFFFFF FFFFFFF |
0 x B F F F F F F F 0 x C 0 0 0 0 0 0 0 0 x F F F F F F F F |
3 2位Windows 2000的内核与6 4位Windows 2000的内核拥有大体相同的分区,差别在于分区的大小和位置有所不同。另一方面,可以看到Windows 98下的分区有着很大的不同。
NULL指针分配的分区:为了帮助程序员掌握N U L L指针的分配情况。如果你的进程中的线程试图读取该分区的地址空间的数据,或者将数据写入该分区的地址空间,那么C P U就会引发一个访问违规。保护这个分区是极其有用的,它可以帮助你发现N U L L指针的分配情况。一般的c/c++编译器都把NULL设置为0,落在这个分区中。
MS-DOS/16位Windows应用程序兼容分区(仅适用Win98):进程地址空间的这个4MB分区是Windows 98需要的,目的是维护MS - DOS应用程序与16位应用程序之间的兼容性。不应该试图从32位应用程序来读取该分区的数据,或者将数据写入该分区。在理想的情况下,如果进程中的线程访问该内存, CPU应该产生一个访问违规,但是由于技术上的原因, Microsoft无法保护这个4MB的地址空间。
在Windows 2000中,16位MS-DOS与16位Windows应用程序是在它们自己的地址空间(其实是在虚拟机中)中运行的,32位应用程序不会对它们产生任何影响。
16位DOS程序的虚拟机就是cmd,16位windows程序使用的是系统虚拟机。
用户方式分区:这个分区是进程的私有(非共享)地址空间所在的地方。
在Windows 2000中,所有的. e x e和DLL模块均加载这个分区。每个进程可以将这些D L L加载到该分区的不同地址中(不过这种可能性很小)。系统还可以在这个分区中映射该进程可以访问的所有内存映射文件。
在Windows 98中,主要的Win32系统DLL(Kernel32.dll,AdvAPI32.dll,User32.dll和GDI32.dll)均加载共享内存映射文件分区中。. e x e和所有其他D L L模块则加载到这个用户方式分区中。多个进程的共享D L L均位于相同的虚拟地址中,但是其他DLL可以将这些D L L加载到用户方式分区的不同地址中(不过这种可能性不大)。另外,在Windows 98中,用户方式分区中决不会出现内存映射文件。
在32位windows中,用户分区的最大寻址空间大约为2G,内核寻址空间为3G。M i crosof t允许x 8 6的Windows 2000 Advanced Server版本和Windows 2000 Data Center版本将用户方式分区扩大为3 G B,内核分区压缩为1G。若要使所有进程都能够使用3 G B用户方式分区和1 G B内核方式分区,必须将/ 3 G B开关附加到系统的BOOT. INI文件的有关项目中。
在x86w/3GB和64位的windows中,若要使用2GB以上的用户空间,该应用程序必须使用/ LARGEADDRESSAWARE 链接开关来创建。
64KB禁止进入的分区(适用于win2k):这个位于用户方式分区上面的64 KB分区是禁止进入的,访问该分区中的内存的任何企图均将导致访问违规。
共享的MMF分区(适用于win98):存放系统DLL、进程共享数据和内存映射文件。
内核方式分区:存放内核代码。用于线程调度、内存管理、文件系统支持、网络支持和所有设备驱动程序的代码全部在这个分区加载。驻留在这个分区中的一切均可被所有进程共享。
在Windows 2000中,这些组件是完全受到保护的。如果你试图访问该分区中的内存地址,你的线程将会产生访问违规,导致系统向用户显示一个消息框,并关闭你的应用程序。
在Windows 98中该分区中的数据是不受保护的。任何应用程序都可以从该分区读取数据,也可以写入数据,因此有可能破坏操作系统。
2.3. 地址空间的区域
当进程被创建并被赋予它的地址空间时&#