精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>电脑技术>>○ DOS>>系统资料>>[转载] Win98 内存管理(二)

主题:[转载] Win98 内存管理(二)
发信人: yangcs()
整理人: yangcs(2000-04-09 11:42:17), 站内信件
【 以下文字转载自 CLanguage 讨论区 】
【 原文由 浪子 所发表 】
Windows 98 的单进程地址空间
  那么,Windows 98 怎样创建单进程私有地址空间呢?你可能首先会想
到根据上下文切换更新 CPU 的 CR3 寄存器。尽管 Windows NT 和其他操
作系统确实是这么做的,但 Windows 98 却没用这种方法。Windows 98只
设置 CR3 寄存器一次(在系统初始化期间),在正常系统操作期间不再管
它。Windows 98 上每个 进程的私有地址空间不是用处理器的 CR3 寄存器
来建立的,而是在上下文切换期间玩弄了一些技巧,建立了内存上下文。

Windows 98 的内存上下文
  Windows NT 为所有每个进程都提供一个私有地址空间,而相比之下,
Windows 98 可就没那么大方了。前边什么地方我们提到过,其中部分原因
就是由于Windows 98 自己就没有那么大方的“预算”。为所有的进程都提
供私有地址空间将为其中每个进程花费 4K 页目录和若干个 4K 的页表。
  Windows 98 采取的方法是创建单个页表集合。在一个进程的线程和另
一个进程的线程之间的上下文切换期间,Windows 98 更新这个页表。每个
进程所看到的视图称为“内存上下文”。部分地址空间是由操作系统的动态
链接库(DLL)构成的,它们由所有的进程共享。引用这部分地址空间(从
2GB-4GB)的页表从来不用改变。而是在上下文切换期间,只有那些与单个
进程私有页相关联的页表项必须改变,即从4MB-2GB。正象许多人期望的那
样,Windows98对页表所做的更改在所有进程看来就象操作系统表演的“魔
术”。每个进程看到的都是某个地址范围内的私有数据以及与其他进程共享
的内存。
  无论操作系统玩弄的是什么技巧,处理器的寻址机制没有变。由操作系
统的内存管理器来确定哪些内存对哪个进程是可见的。特定的代码或数据页
可以映射到单个进程的地址空间,也可以映射到多个进程的地址空间。多亏
有了 Intel 处理器的灵活性,Windows 98 二者都可以做到。
  为与 Windows 3.x 兼容,Windows 98 上的 Win16 程序没有私有地
址空间,而是运行于通用地址空间。这就允许仍使用 Win16 程序一贯使用
的内存共享类型:自由访问内存指针、对象句柄和内存句柄。当把 Win16 
程序转换到 Win32 API 时,任何 Win16 风格的内存共享都必须更新为支
持与 Win32 兼容的共享技术。
  对于 Win32 程序来说,Windows 98 和 Windows NT共享一种通用的
可执行文件格式。这很关键,因为在两个操作系统中,可执行文件都是作为
内存映射文件加载的。本章后面将讲述,这个机制依赖于虚拟内存管理器把
磁盘文件和一定范围内的内存地址联系起来。只有对应的内存地址被访问到
时,才会从磁盘中读入页。
  Win32 可执行文件格式称为可移植执行格式。它是为各种微软操作系统
创建的几种可执行文件格式之一。下表总结了用于其他微软操作系统的可执
行文件格式。“标志”列指的是文件头中的两个字符的代码,用来区分可执
行文件的具体类型。

            各种微软操作系统使用的可执行文件格式
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  可执行文件类型    标志     说明
—————————————————————————————————
                            Mark Zbikowski 的可重定位可执行文
  MS-DOS 程序       MZ      件格式。 Mark创建了 MS-DOS 2.0 可
                            执行文件格式,并通过用自己名称的首
                            字母作为这种可执行文件的标志,使自
                            己可以流芳百世。
—————————————————————————————————
                            新的可执行文件是面向段的 Win16 程
  Win16             NE      序。 OS/2 1.x为其 16 位程序使用与
                            此相同的文件格式。
—————————————————————————————————
                            可移植执行文件是 Win32 程序。 这个
  Win32             PE      文件格式用于为 Windows 98 和 Win-
                            dows NT 建立的 Win32 程序。
—————————————————————————————————
  Windows 虚        LE      线性可执行文件是32位设备驱动程序,
  存驱动程序                有时候称为VxD,在 Windows 3.0 中引
                            入,至今仍被 Windows98使用。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    从进程地址空间的角度看,Windows 98和 Windows NT 还共有另外一
个特色:使用“未用”地址范围。这些是非法地址,它们的存在是为帮助捕
获各种类型的指针错误,特别是 NULL 指针的使用。Windows NT 上有两个
这样的区域,每个64K。一个在基本地址空间(地址从 0~10000h)。另一
个在应用程序的地址空间的顶部(从 7FFF0000 到 7FFFFFFF)。
  另一方面,Windows 98 的“未用”区只有一个,在地址空间底部的4M
区域。对这个范围的任何内存访问都会引起一个处理器异常(在 Windows 
NT 中也是这样)。两个操作系统都会终止任何发生不可处理异常的进程。
在 Windows 98“未用”区内隐藏的是实模式 MS-DOS 部分,还为 Win16
程序保留了一块区域。
  一个有趣的问题是,为 Win16 保留的“未用”区只有 64K。它的存在
是为帮助捕获访问 0 段的指针。除了这一类似之处以外,Win16 程序的内
存视图和 Win32 程序看到的大相径庭。为保持向后兼容,运行在 Windows
98 上的 Win16 程序和它在 Windows 3.1 上运行相比,具有几乎相同的
内存视图。
  Windows 98 和 Windows NT 另一个共同特色是 DLL 映射到进程地址
空间的方式。在两个系统中,特定于应用程序的 DLL 映射到为应用程序保
留供其专用的地址范围,即 2GB 以下。
  在 Windows 98 中,唯一的例外是系统 DLL,它提供了构成  Win32 
API 的所有函数。它们被载人 2GB~3GB 间的共享内存区。根据其性质,
这些 DLL 由所有的 Win32 应用程序共享。同样,使得它们驻留在被所有
进程共享的地址空间部分很有意义。
  正如你所看到的,在提供 Win32 进程访问的内存的方式上,Windows
98 和 Windows NT 有一些类似之处。现在,让我们看一看它们的区别。

Windows 98 和 Windows NT 之间的进程内存区别
  Windows 98 和 Windows NT 之间的主要区别在于安全性。Windows
NT 在进程间设立了严格的屏障。与之相比,Windows 98 更信任并沿用了
从 MS-DOS 和各种 16 位版本的 Windows 开始的惯例。尽管Windows 98
为每个进程提供了一个私有地址空间,但在共享内存区域中的所有内容都是
可以完全访问的。
  Windows 98 从这种开放且信任的方式得到的主要利益是比 Windows
NT 需要的资源更少。完善的楼房安全系统需要更多的资源,如配线、电流、
安全员和摄象相机,同样的道理,一个更安全的操作系统也需要更多的资源。
Windows 98 的建立是为了在一个拥有4M RAM(尽管 8M 内存可能更现实)
的 80386 处理器上运行的。而要支持其完善的功能,Windows NT 需要至
少一个 80486 和 12 MB RAM。(尽管更多的 RAM,例如 16 MB到24 MB,
会使整体性能有所不同。)
  Windows NT 需要更多的处理器资源,是因为它的 GUI 系统大部分在
Win32 进程的地址空间的外面实现。例如,每个创建窗口或绘图的调用都会
发出在另外的进程中或在调用进程的另外的地址空间中实现的请求。这种进
程的名称就是“Win32 子系统”。在独立的内存空间中运行,使核心操作系
统组件可以很安全遭偶然的和有意的破坏。这种安全性的代价就是性能,也
就是说,与诸如 Windows 98 之类的更开放的系统相比,获得同样的性能需
要更多的资源。
  Windows 98 把所有系统库都放在 2GB~3GB 的共享内存区中。不论好
坏,每个 Win32(和 Win16)程序都可以很容易地接触到所有的系统库。当
Win32 程序运行在 Windows 98 上时,它只需一个简单的函数调用(可能
还要加一条跳转指令)就可以接触真正的系统函数。在 Windows NT上,一
般在函数调用和实际执行功能的代码之间还有一个上下文切换。(然而,在
Windows NT 上的简单的查询函数和在 Windows 98 上一样快。)
  由于设计时处处考虑安全性,所队 Windows NT 不能轻易地共享内存。
例如,它不象在 Windows 98 中那样有公有的共享内存区。如果不明确指出
什么可以共享,那么什么都不允许共享。这种增强的安全性使 Windows NT
比Windows 98更加强健。你更能确信共享数据不会被不应该看到的人看到。
  另一方面,Windows 98 上共享内存是从共享内存区中分配的,系统中
的每个进程都可以立即访问它。如果对你来说安全性很重要,这可就成了问
题。除了数据的地址,进程读写存储在共享区的数据再不需要任何别的东西。
(可以毫不费劲地编写一个“蛮不讲理”的例程,扫描共享地址以查找感兴
趣的信息。)
  如果不考虑安全性,不同的内存共享手段也会给编程带来难题。(安全
性问题当然很重要,但安全性不是我们这里要讲的重点。)一个问题就是如
何在两个既可以运行于 Windows 98 也可以运行于 Windows NT 的 Win32
程序之间共享内存。你将使用同样的 API 访问共享内存。那么,有什么不
同呢?
  它们的不同产生于这样一个事实:Windows NT 中的共享对象可以被映
射到不同进程中的不同地址。设想有一个 64K 的共享缓冲区。当它对 Wi-
ndows NT 中的三个不同进程都可用时,在一个进程中可能被映射到地址 
800000h,在第二个进程中可能是 850000h,在第三个进程中可能是 900-
000h。尽管你可以试着把共享对象映射到一个特定的位置,但这很困难,并
且也许根本不可能,这取决于这个对象的大小和每个地址空间的内容。在 
Windows NT 上,因为每个进程的地址空间都独立于所有其他进程的地址空
间,所以单个内存对象可以映射到不同 Win32 进程的不同位置。
  在 Windows 98 上,一个进程创建的共享对象对所有的进程都是可见
的,且在同一地址处。正如前面提到过的,这个地址总在 2GB~3GB 之间。
在 Windows 98 上,当两个(甚至 200 个)其他 Win32 进程访问共享
内存时,总是在相同的地址处。
  我们这里的问题是怎样编写一个 Win32 程序,使它运行于两个操作系
统上时都可以共享内存。简单地回答就是避免在 Win32 程序间直接传递地
址,并确保使用正确的内存共享 API。还有,当编写内存共享程序时,一定
要在 Windows NT 上进行测试。毕竟,这是两个操作系统中条件更苛刻的
一个。当我们更深入地讨论内存共享时,还将提供一些编写兼容于所有 Wi-
n32 平台的内存共享代码的技巧。
  Windows 98 和 Windows NT 都提供的一个对 Windows 3.1 的重要改
进是为 Windows 程序员提供了系统内存清理能力。这就是我们要讨论的下
一个主题。

--
欢迎您到C语言版来!
欢迎光临BBS系统版!

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.99.93.30]
--
※ 转载:.月光软件站 http://www.moon-soft.com.[FROM: 210.72.45.12]

[关闭][返回]