11、Windows API 内存管理(1)
一、相关概念
1、内存主要储存程序运行时所需的机器代码、数据等内容。
内存的最小存储单元是字节,内存中的每一个字节都有一个地址。在32位系统上,使用32位的数来表示内存地址,因此一共可以表示232 (4294967296-4G)个字节。
2、地址
(1)地址空间。
系统中所有可用的内存地址的集合称为地址空间。比如,如果可以使用4GB的内存,那么其地址空间就是0x00000000~0xFFFFFFFF。
(2)物理内存。
硬件系统中真实存在的存储空间称为物理内存,物理内存的访问通过硬件系统总线进行的。
但不是每台32位的机器都具有4GB的物理地址空间,因此物理地址空间不一定是0x00000000~0xFFFFFFFF,比如在物理内存为1GB的系统上,就可能只有0x00000000~0x3FFFFFFF的地址可以使用。
(3)虚拟地址空间。
为了访问内存的统一和方便,操作系统允许其上运行的程序访问所有的4GB内存空间中的地址。因此操作系统必须进行一些必要的地址转换工作,将程序访问的地址转换为物理内存中的真实物理地址,然后进行数据的存取。操作系统进行转换后,供程序使用的地址空间称为虚拟地址空间。在32位系统上,可以使用的虚拟地址空间大小是4GB。
当然,由于虚拟地址空间可能比真实物理地址空间大,系统会将部分虚拟地址空间中的地址转换为硬盘中的数据,在必要时将物理内存中的数据与硬盘中的数据进行交换。
这种地址转换和数据交换是通过分页和分段机制实现的。
(4)进程的内存空间:用户内存空间与内核内存空间。
Windows操作系统中的每个进程都有属于自己的虚拟地址空间。32位的Window操作系统将4GB(在64位系统上,这个值达到了8TB)的虚拟内存划分为两个部分,进程使用2GB,称为用户进程空间;内核使用2GB,称为系统地址空间或内核地址空间(也可设置为用户进程空间使用3GB,内核使用1GB,这里只讨论各为2GB的情况),用户空间的地址范围为0x00000000~0x7FFFFFFF,内核空间的地址范围为0x80000000~0xFFFFFFFF。虚拟地址空间在进程上是封闭的,进程只能访问属于自己的地址空间,如果要访问其他进程的地址空间需特殊的机制。
3、分页与分段内存管理、内存映射与地址转换
32位地址的高10位称为页目录索引(Directory)、次10位称为页表索引(Table),余下的12位为偏移(Offset)。如果只取前两个部分的20位,末位补0,那么其可能指向的地址都是4KB( 212)对齐的,也就是页的基地址。所以32位中的前20位定位了页的基地址(PFN),而最后12位是地址在页内的偏移。
相当于先选定那本书,再选定那本书的页数,再选中页中的那行。
在地址转换的过程中,还涉及一个关键的系统寄存器CR3。CR3寄存器中的高12~32位保存了页目录索引在物理内存中的地址。
地址转换经过了如下过程。
(1)从CR3寄存器的12~32位中取出地址,末位补0,构成一个32位的地址,此地址是页目录所在物理内存的基地址(因此页目录在内存中肯定是4KB对齐的)。
(2)以线性地址中的高10位的页目录索引(Directory)中数据为偏移,加上上一步得到的页目录所在物理内存的基地址,在页目录中找到相应的页目录项(PDE)。
(3)页目录项中包括了页表的基地址,线性地址中的页表索引(Table)是页表中的偏移,找到页表项(PTE)。
(4)页表项(PTE)中存储的是物理地址空间中的页面的地址(PFN),如果PFN指向的页面是无效的(不在物理内存中),那么会在系统内核中引起页错误,系统内核会进行页面调度,将物理内存中暂不使用的页面交换到硬盘中,将硬盘中需要访问的页面交换到物理内存中,使用PFN指向的页是有效的。
(5)现在已经找到了线性地址所对应的物理地址所在的页的基址。
(6)在物理页地址的基础上,加上线性地址末12位的偏移,可得到线性地址与物理地址的对应。
从中可以看出地址转换是以页为单位的,也就是线性地址与所对应的物理地址的页基地址(PFN)是会变化的,在页内的偏移地址是不会发生变化的。
每一个页目录项对应了一个页表,一共有210个页目录。每一个页表项对应了一个内存分页,每个页表是最多可以表示210个页表。最多一共是多有220个页。