|
Memory Management(1)
Windows 95 System Programming SECRETsXML:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> (Windows 95 系统程序设计 大奥秘) 原著:Matt Pietrek 笔记:Simon wan 内存管理(Memory Management)Windows 95 之中的Win32 行程地址空间Windows 3.x 之中,所有程序都在同一个地址空间中执行。于是任何程序都很容易读取另一个程序的内存。更糟的是,程序还可以改变其它程序的内存内容,这就提供给那些有臭虫的程序一张通往地狱的车票啰。例如,16 位 Windows 程序甚至在 Windows95 中可以取得 16 位 USER DGROUP 的selector 并随意写些垃圾进去。于是窗口系统只好对你说拜拜了。 Windows 95 给予每一行程一个独立地址空间。所谓「独立地址空间」,我意思是程序只能看到它自己的内存,其它行程所使用的内存是不可处理的。更精确地说,Windows95 内存管理器使用 CPU 「以分页为基础」的内存管理哲学,确保只有目前行程所拥有的内存才会被映像到CPU 的 4GB 地址空间中。其它行程所拥有的 RAM 并不会出现在目前行程的page tables 中。这样做的最大好处是,一个问题程序最多只能破坏它自己,不会影响其它人。 为恐你对这个 Windows 新性质太过兴奋,我必须告诉你,它其实一点也不新。Unix 行之有年矣,Windows NT 亦复如此。我们只能说,微软目前主推的桌上型操作系统拥有了高级操作系统的最基础性质。至于 Win32s,这个 Win32 家族中同父异母的姊妹,并不使用分离地址空间。 虽然把每一个行程的内存分隔开来是很重要的,但某些内存还是需要被所有行程共享。也就是说所有行程的线性地址空间中的某些页应该被映像到相同的 RAM 身上。为什么?最好的例子就是 system DLLs。每一个行程都需要 KERNEL32.DLL,如果每一个行程都载入一份崭新的 KERNEL32.DLL, 那将是无可置信的超级大浪费。因此KERNEL32(以及 USER32 等其它 system DLLs)应该驻扎在共享区域中。当 Windows 作业系统切换 page tables 以便执行另一个行程,它会把映像到共享内存的那些 page table留下不动。我将以其它例子说明共享内存的必要性。 由于 Windows 95 把不同行程的内存都分隔开来,所以对「Windows 95 如何布置4GB地址空间」的任何讨论都将离不开所谓的 memory context 观念。Memory context 基本上是一系列的 RAM pages,以及它们所映像的线性地址。用另一句话说,memory context 是操作系统给予一个行程的线性地址的视野(view)。 每一个行程有它自己一套 memory context。当 Windows 95 排程器将某个行程暂停而让另一个行程执行,它必须把 memory context 也切换过来。由于每一个行程有自己一套memory context,所以有时候它又被称为 process context。有时候它也被称为 address context。不论你把它叫作什么,记住一点,地址本身没有意义,除非你指明这个地址在哪一个 memory context 中。 从最上层来看,Windows 95 的 Win32 行程的内存布局十分简单。在 4GB 地址范围中,最底部的 2GB(0~7FFFFFFFh)保留给应用程序,2GB 以上(80000000h~FFFFFFFFh)则保留给操作系统。这两部份又都有细部切割。图5-1 显示 4GB 地址空间中的各个细目。如果你有 Windows 95 DDK (译注:Device Development Kit),请你阅读线上说明文件中的 "Arenas" 主题中的 “Page Mapping and Address Spaces” 一节。 第一个 4MB 地址空间是给系统虚拟机器中的每一个行程共享。其中位于 1MB 之下的那一部份,内含 MS-DOS 的内存映像(memory image),在 Windows 95 启动时载入。1MB 之下的有趣东西还包括 16 位global heap 的较低部份。一如我在 WindowsInternals 第2章所说,Windows 3.1 中的所有 16 位 heap 节区的线性地址,不是在1MB 之下就是在 2GB 之上。如果它是以 GMEM_FIXED 属性配置而得,那么常常就是在 1MB 之下。你会在地址空间的最初 4MB 中看到许多 16 位system DLLs,因为它们之中有许多(例如 KRNL386)需要「fixed 并且pagelocked」的内存。这是很重要的一点,稍后我还会再讨论。 下一个区域是 4MB 到 2GB。这是 Win32 行程所使用的地址空间。每一个 Win32 行程把它自己的码、自己的数据、自己的资源映像到这将近 2GB 的范围来。当memorycontext 的切换动作发生,其实就是换另一组 pages,映射到这个范围。除非特别指定,否则映像到此区域的 RAM pages 不能够被其它行程存取。除了应用程序的码和数据,它所用到的任何 DLLs 的码和资料也放在此区。在这里面你还可以发现应用程序的heap和stack(每一个执行绪有一个stack)。
|