天天看点

windows 核心编程 (内存体系结构)

1、进程的虚拟地址空间

    每个进程都有自己的虚拟地址空间。对于32位进程来说,这个地址空间大小为4G。

    每个进程都有自己的专有地址空间,当进程中的各线程运行时,它们只能访问属于该进程的内存。线程既看不到属于其他进程的内存,也无法访问它们。

2、虚拟地址空间的分区

    每个进程的虚拟地址空间被划分成许多分区。

    x86 32位windows系统进程地址空间分区:

            空指针赋值分区:    0x00000000 ~ 0x0000FFFF    64k

            用户模式分区:       0x00010000 ~ 0x7FFEFFFF    2G - 64k - 64k

            64k禁入分区:       0x7FFF0000  ~ 0x7FFFFFFF    64k

            内核模式分区:       0x80000000 ~ 0xFFFFFFFF    2G

3、地址空间中的区域

    当系统创建一个进程并赋予它地址空间时,可用地址空间中的大部分都是闲置的或尚未分配的。

    为了使用这部分地址空间,我们必须调用VirtualAlloc来分配其中的区域。

    分配区域的操作被称为“预定”(reserving)。

    当应用程序预定空间区域时,系统会确保区域的起始地址正好是分配粒度(allocation granularity)(x86平台分配粒度大小为64k)

    当应用程序预定地址空间中的一块区域时,系统会确保区域的大小正好是系统页面大小的整数倍。(x86系统页面大小为4k)

    释放地址空间区域,通过调用VirtualFree函数来完成。

4、给区域调拨物理存储器

    为了使用所预定的地址空间区域,我们必须分配物理存储器,并将存储器映射到所预定的区域。这个过程称为“调拨”(committing)物理存储器。物理存储器始终都以页面为单位来调拨。通过调用VirtualAlloc函数来将物理存储器调拨给所预定的区域。

    当我们调拨物理存储器给区域时,并不需要给整个区域都调拨物理存储器。

    当程序不再需要访问所预定区域中已调拨的物理存储器时,应该释放物理存储器。这个过程称为“撤销调拨”(decommitting),通过使用VirtualFree函数来完成。

5、物理存储器和页交换文件

    磁盘上的文件一般称为“页交换文件”(paging file),其中包含虚拟内存,可供任何进程使用。

    为了能够使用虚拟内存,操作系统需要CPU的大力协助。当线程试图访问存储器中的一个字节时,CPU必须知道该字节是在内存中还是在磁盘上。

    最好是把物理存储器看成是保存在磁盘(通常是硬盘)上的页交换文件中的数据。当应用程序调用VirtualAlloc函数来把物理存储器调拨给地址空间区域时,该空间实际上是从硬盘上的页交换文件分配得到的。

    系统中页交换文件的大小是决定应用程序可用内存总量的最重要的因素,机器实际装备的内存总量对它的影响相对较小。

    系统需要在内存和页交换文件之间复制页面的频率越高,硬盘颠簸(thrash)得越厉害,系统也运行得越慢(颠簸是指操作系统把所有时间都花在页面文件和内存之间交换数据上,导致没有时间运行程序。)通过给计算机添加更多的内存,我们可以减少应用程序运行时可能颠簸的次数,提高应用程序性能。

6、不在页交换文件中维护的物理存储器

    当用户要求执行一个应用程序时,系统会打开该应用程序对应的.exe文件并计算出应用程序的代码和数据的大小。然后系统会预定一块地址空间,并注明与该区域相关联的物理存储器就是.exe文件本身。系统并没有从页交换文件中分配空间,而是将.exe文件的实际内容(或文件映像)用作程序预定义的地址空间区域。这样一来,不但载入程序非常快,而且页交换文件也可以保持一个合理的大小。

    当把一个程序位于硬盘上的文件映像(即一个.exe或DLL文件)用作地址空间区域对应的物理存储器时,我们称这个文件映像为“内存映射文件”。

7、页面保护属性

    内存页面保护属性分为读,写,执行等基本属性。

    这里还存在一种"copy on write"(写时复制)属性,它们存在目的是为了节省内存和页交换文件的使用。

    windows支持一种机制,允许两个或两个以上的进程共享同一块存储器。它让所有的应用程序实例只能读取其中的数据或执行得代码。如果某个应用程序修改并写入一个存储页,那么这等于修改了其他实例正在使用的存储页,最终导致混乱。为了避免混乱,操作系统会给共享的存储页指定写时复制属性。当系统把一个.exe或.dll映射到一个地址空间的时候,系统会计算有多少页面是可写的。然后系统会从页交换文件中分配存储空间来容纳这些可写页面。除非应用程序正的写入可写页面,否则不会用到页交换文件中的存储器。

8、数据对齐

    只有当访问已对齐的数据时,CPU的执行效率才最高。

    把(数据的地址) %(取模)(数据所占空间的大小),如果结果为0,那么数据是对齐的。

    如果CPU要访问的数据没有对齐,那么会有两种可能。第一种可能是CPU会引发一个异常,另一种可能是CPU会通过多次访问已对齐的内存,来取得整个错误数据。

    x86 CPU的EFLAGS寄存器内有一个特殊的标志位,AC(alignment check 对齐检查)。默认情况下, 这个标志位在第一次给CPU通电时被清零。如果标志为0,那么CPU会自动执行必要的操作来访问错位数据。但是如果该标志位为1,那么一旦程序试图访问错位数据,CPU就会触发INT 17H中断。

    x86 版本的windows从来不会改变这个标志,所以应用程序在x86处理器上运行时,绝对不会发生数据错位的异常。