16 位 Windows 内存管理:复杂机制与 OS/2 的对比及测试工具揭秘
OS/2 博物馆资源导航
OS/2 博物馆(http://www.os2museum.com/wp/)涵盖 OS/2、复古 PC 计算及杂谈内容。其网站提供了丰富的资源链接,包括主页、关于(含需求列表)、OS/2 历史(包含 OS/2 起源、各版本介绍、时间线、资料库等)、DOS 历史、NetWare 历史、Windows 历史、PC UNIX 历史等。
Win16 内存管理文章发布信息
《Win16 内存管理》发布于 2026 年 6 月 5 日,作者是 Michal Necasek。这是一篇知识库类文章,源于对 16 位 Windows 内存管理机制的深入探究。在 Windows 3.0 问世前,人们认为应用开发者用高级语言开发,开发工具处理底层细节,早期面向 Windows 开发者的资料也多聚焦窗口、图标、菜单等,对内存管理提及较少,但编写复杂 Windows 应用时,内存管理至关重要。
Windows 内存管理简介
Windows 从一开始就是出色的覆盖管理器,因当时典型 PC 内存有限,需将活跃内存段保留在物理 RAM 中,有丢弃和重新加载不常用段的机制。由于 8086 和 80286 系统在 Windows 3.0 之前不支持分页,所以未采用分页技术。对于简单应用程序,Windows 段的可移动性几乎透明,但编写 Windows 应用时会发现情况并非如此简单,如窗口过程需声明为 `FAR PASCAL` 并从应用程序可执行文件中“导出”。Windows 采用并扩展了“New Executable”(NE)格式,该格式以段为导向,支持“导入”和“导出”,窗口过程需导出以便 Windows 处理。
内存移动机制
Windows 内存管理围绕段展开,段是不超 64KB 的连续内存块,通过“句柄”标识,类似于保护模式选择器。`GlobalAlloc` API 从全局堆分配连续内存并返回段句柄,应用程序访问段内容需调用 `GlobalLock` API 锁定段,完成访问后调用 `GlobalUnlock` 解锁。Windows 除非必要不会移动或丢弃段,但解锁后可能随时操作。
段标志属性
Windows 段有“固定的”或“可移动的”、“可丢弃的”或“不可丢弃的”属性。可移动段未锁定时可被 Windows 移动,固定段保持原位;代码段通常可丢弃,数据段往往不可丢弃,但应用程序可允许可写数据段可丢弃。
DLL 相关情况
20 世纪 80 年代中期,Microsoft Windows 是最早支持动态链接库(DLL)的系统之一。Windows DLL 是 NE 格式映像,不能直接执行,由其他进程加载和调用,Windows 大部分功能以 DLL 形式实现。DLL 导出例程供应用程序调用,可在链接或动态加载时引用。Windows 采用两级命名空间管理 DLL 符号,避免名称冲突。DLL 没有自己的堆栈,使用调用者的堆栈,编译器需为 DLL 生成特定代码。
秘密开关情况
Microsoft C 从 3.0 版开始支持 Windows 开发,但多年来这种支持几乎是秘密进行的,Windows 特定开关在编译器文档中被省略或引导用户参考 Windows SDK。自 1985 年的 Microsoft C 3.0 起有 `/Aw` 和 `/Gw` 开关,`/Aw` 开关用于生成 DLL 时指定 SS != DS 且函数入口处不重新加载 DS;`/Gw` 开关为远函数生成 Windows 序言和尾声。
Windows 序言和尾声解析
Windows SDK 附带的 `CMACROS.INC` 文件说明了 Windows 特定的函数序言和尾声,但难以阅读。以 Microsoft C 3.0 生成的代码为例,序言看似做了很多无用功,但关键是在不需要时无害。如果函数从 Windows NE 模块导出,Windows 加载器会修补前三个字节,更新序言使导出函数指向新地址。Windows .DEF 文件中的 `NODATA` 关键字可告诉 Windows 不要修补函数序言。BP 的递增和递减是为了让 Windows 遍历堆栈,确保堆栈帧格式可被理解。
与 OS/2 的比较
16 位 Windows 与 16 位 OS/2 有很多相似之处,都使用相同可执行格式,采用基于段的内存管理,使用相同开发工具。但因 OS/2 使用保护模式,对程序员协作要求低,应用程序无需特殊序言和尾声代码,也无需显式导出窗口过程等,减少了编程错误来源。OS/2 DLL 入口点需特殊序言设置 DS 寄存器,但不需要操作系统特殊支持。
测试工具情况
Windows SDK 提供测试 Windows 内存管理的工具。Windows 1.0 SDK 中的 SHAKER 工具用于“摇晃”内存,揭示隐藏的内存管理错误;HEAPWALK 工具可显示当前分配的段及其所有者,模拟内存不足情况。Windows 3.0 SDK 仍有这两个工具,Windows 3.1 SDK 用 Stress 工具取代 Shaker 工具,测试应用程序在资源不足条件下的行为。
总结
16 位 Windows 引入了复杂的内存管理系统,因缺乏硬件支持,应用程序程序员需严格遵守规范,否则可能出错。
文章评论情况
有三位读者对文章进行了评论。David C. 认为文章很棒,回忆起编程往事,还提到早期 Mac OS 也使用基于段/句柄的内存管理器,猜测开发原因相同并对公司间代码共享情况感兴趣;Richard Wells 回忆 Win2 时代的拼写检查器,指出压缩可执行文件扼杀了可丢弃内存概念,OS/2 1.x 保存丢弃段到磁盘的方法有小问题;Michal Necasek 认为公司间没有代码共享,Windows 开发是因 GUI 系统 RAM 不够用。
