第十三章 内存体系结构
本章内容
13.1 进程的虚拟地址空间
13.2 虚拟地址空间的分区
13.3 地址空间中的区域
13.4 给区域调拨物理存储器
13.5 物理存储器和页交换文件
13.6 页面保护属性
13.7 实例分析
13.8 数据对齐的重要性
操作系统所使用的内存体系结构是理解操作系统如何运作的关键。当我们使用一个新的操作系统时,脑海中会涌现出许多问题。
比如:
1)怎样在两个应用程序之间共享数据?
2)系统把我们需要的数据保存在哪里了?
3)怎样才能让应用程序更高效的运行?
13.1 进程的虚拟地址空间
每个进程都有自己的虚拟地址空间,对32位进程来说是4GB (0x0000`0000 ~0xFFFF`FFFF)
对64位应用程序来说,是 16EB (0x0000,0000,0000,0000 ~ 0xFFFF,FFFF,FFFF,FFFF)
因为每个进程都有自己的专有地址空间,当进程中的各线程运行时,他们只能访问属于该进程的内存。线程既看不到属于其他进程的内存,也无法访问它们。
每个进程对内存地址的访问都是进程自己的数据结构。互不干扰。
但是这些内存地址仅仅是虚拟地址,还需要和物理地址做映射,否则会导致访问违规(access violation)。
13.2 虚拟地址空间的分区
每个进程的虚拟地址空间被划分成许多分区(partition),由于依赖操作系统的实现,随着windows版本不同略有不同。
32位和64位的windows内核分区基本一致,唯一不同在于分区大小和分区的位置。
13.2.1 空指针赋值区
在32位模式下,是0x00000000~0x0000FFFF的闭区间。其目的是为了帮助程序员捕获对空指针的赋值。
如果进程中的线程试图读取或写入这一分区的内存地址,就会引发访问违规。
例如一下代码检查不够彻底,没考虑malloc分配失败的情况。
int *pnSomeInteger = (int*)malloc(sizeof(int));
*pnSomeInteger = 5;
试图访问0x00000000 会触发异常。
13.2.2 用户模式分区
这一分区就是进程地址空间的驻地。可用地址区间和用户模式分区的大小取决于cpu的体系结构。
进程无法通过指针来读取,写入或以任何方式,访问驻留在这一分区中其他进程的数据。
对于所有应用程序来说,进程的大部分数据都保存在这一分区。由于每个进程都有自己的数据分区,因此一个应用程序破坏另一个应用程序的可能性就很小。
(第一次看到32位进程地址空间时,会发现进程可用的地址空间的数列居然不到整个进程地址空间的一半。难道内核模式分区真的需要整个地址空间的上半部分么?实际上是的)
系统需要用这一空间来存放内核代码,设备驱动程序代码,设备输入/输出高速缓存,非页缓冲池分配表(non-paged pool allocation), 进程页面表,等等。
事实上Microsoft已经将内核压缩到这2GB空间中。在64位windows中,内核终于得到它真正需要的空间。
1. 在X86 Windows下得到更大的用户模式分区。
有些应用程序(如Microsoft SQL Server)会收益于大于2GB的用户模式地址空间。可寻址更多的数据由助于提升应用的性能。
x86版的windows提供了一种模式来增大用户模式分区,但最多不超过3GB。
为了让所有应程序使用大于2GB的用户模式分区和小于1GB的内核模式分区,要堆Windows启动配置数据(boot confiuration data 简称BCD)做设定。
例如bcdedit /set IncreaseUserVa 3072 将告知Windows为所有进程保留3GB用户模式地址空间和1GB的内核模式地址空间。
IncreaseVa的最小值是2048, 默认值就是2GB
如果要取消该参数的设定,执行 bcdedit /deletevalue IncreaseUserVa
(在早期版本的Windows中,因为不允许访问2GB以上的地址空间,因此一些有创意的开发人员对此加以利用