Unix 痛恨者手册往事
最后更新于
那是 1987 年,Michael Travers 还是麻省理工学院媒体实验室的一名研究生,正在迈出通往未来的第一步。多年来,Travers 一直在他那台 Symbolics Lisp 机(昵称 LispM)的控制台上编写庞大且优美的程序,LispM 是实验室的两台最先进人工智能工作站之一。但这一切即将结束。出于成本和效率的考虑,媒体实验室决定淘汰 LispM。特拉弗斯发现,如果他还想在麻省理工进行研究,就必须使用实验室的 VAX 大型机。
这台 VAX 运行的是 Unix。
麻省理工有着悠久的传统,维护着专门针对特定操作系统的邮件列表。这些列表面向系统黑客,例如 ITS-LOVERS,专为麻省理工人工智能实验室的 Incompatible Timesharing System(不兼容分时系统)的程序员和用户组织。这些列表针对的是专家,是那些能够且确实编写过自己的操作系统的人。Michael Travers 决定创建一个新的列表,他称之为 Unix 痛恨者:
日期:1987 年 10 月 1 日 星期四 13:13:41 EDT
发件人:Michael Travers
收件人:Unix 痛恨者
主题:欢迎加入 Unix 痛恨者
遵循 Unix 痛恨者的传统——这是一个面向那些难以接受最新操作系统技术的倔强人士的邮件列表。
如果你实际上并不是 Unix 痛恨者,请告诉我,我会将你移除。请添加你认为需要情绪发泄渠道的其他人。
Michael 发送给 Unix 痛恨者的第一封信中,包含了另一位刚加入 Unix 古拉格的新成员写的一篇关于 Sun 的合理愤怒控诉:John Rose,是马萨诸塞州一家知名计算机制造商的程序员(该公司律师承诺只要我们不公布公司名称,就不会起诉我们)。和 Michael 一样,John 最近也被迫放弃了 Lisp 机器,改用运行 Unix 的计算机。历经一周的工作受阻,他向公司内部支持邮件列表发送了这条消息:
日期:1987 年 2 月 27 日 星期五 21:39:24 EST
发件人:John Rose
收件人:sun-users,systems
主题:Sun 的利弊
好吧,我这里正好有点空,因为我的 Sun 机上的编辑器窗口在我眼前突然消失了,带走了我一天的 Emacs 编辑。
所以,问题自然来了,Sun 究竟有什么优点和缺点?
这是我用 Sun 的第五天。巧合的是,我的 Emacs 也是第五次崩溃。所以我觉得我开始有点了解 Sun 的优点了。
Sun 的一个不错的地方是它们启动真的很快。如果你还没见过它启动,你应该看看。对我们这些 LispM 要整个上午才能启动的人来说,简直令人振奋。
另一个好处是 Sun 的简洁。你知道 LispM 总是跳进那个糟糕、复杂的调试器里,显示令人困惑的回溯信息,还期待你告诉它下一步怎么做?Sun 总是知道该怎么做。它们会生成核心文件并终止出错进程。还能有什么比这更简单?如果有窗口,它就会立刻关闭。(我刚才是不是感到一阵寒意?)
这种简洁大大减少了调试时间,因为你立刻放弃了找出问题的希望,只能从头开始重新执行你刚才正在进行的复杂任务。实际上,这个时候,你干脆重启吧。去吧,启动真的很快!
Sun 启动快的一个原因是它们加载的东西更少。LispM 把代码加载到内存里时,还加载了大量调试信息。比如,每个函数都会记录参数和局部变量的名字、所有宏展开成该代码的名称、文档字符串,有时还有解释型定义,纯粹是为了保险起见。
哦,每个函数还会记住它定义在哪个文件里。你完全不知道这有多有用:有一个编辑器命令叫“meta-point”,它可以让你立刻跳转到任何函数的源代码,过程流畅不中断。所有函数,都不是某些特别预设的函数。同样,还有一个按键可以瞬间显示函数的调用序列。
过去几天我一直登录到 Sun 上,我的 Meta-Point 反射动作依然不减,但完全被挫败了。
我正在做的程序大约有 80 个文件。想要编辑函数 Foo 的代码,我得切换到 shell 窗口,在各种文件中用 grep 搜索 Foo 的名字。然后我得输入合适的文件名。然后我得改正拼写错误。最后再在文件里搜索。过去只需五秒的事,现在要花一两分钟(不过朋友之间一个数量级的差别算什么呢?)
到这时候,我真想看看 Sun 的最佳表现,于是忍不住想重启它几次。
Unix 有一款很棒的命令叫“strip”,用它可以强制程序去掉所有调试信息。Unix 程序(比如 Sun 的窗口系统)通常都是被 strip 过的,因为调试信息占用磁盘空间,且会拖慢启动速度。这意味着你不能用调试器调试它们。但这无所谓,你见过 Unix 的调试器吗?真的。
你知道所有标准的 Sun 窗口应用程序(“tools”)其实是一个庞大的 3/4 兆字节二进制文件吗?这让这些工具共享代码(里面有大量代码)。Lisp 机器也是通过这种方式共享代码的。工作站保护我们内存投资的方式就是代码共享,挺不错的。
但所有标准的 Sun 窗口应用程序(“tools”)都不支持 Emacs。没法给 Unix 应用程序打补丁;你必须有源代码,才能打补丁,然后从源代码重新生成应用程序。
但我真想让 Sun 的鼠标能跟 Emacs 通信。于是我找来了几百行代码(来自 GNU 源码),编译并链接到所有标准 Sun 窗口应用程序(“tools”)共享的那段代码里。结果很快!Emacs 终于能用鼠标了!就像 LispM 一样;我记得当年为了让 LispM 的终端程序和 Emacs 配合也做过类似的破解。只用了大约 20 行 Lisp 代码(虽然这比起刚才几百行代码简单多了,不过朋友之间数量级差别算什么呢?)
好了,我运行了我的 Emacs-with-mice 程序,开心地玩着鼠标。不久 Emacs 开始报错,提示“内存耗尽”和“段错误,生成核心转储”。小小的 Unix 控制台安慰自己说“clntudp_create:内存不足”。
最终,我的 Emacs 窗口决定该结束一天的工作了。
发生了什么?显然是两件事。首先,当我为窗口系统创建自定义补丁,使鼠标点击能够传递给 Emacs 时,我生成了另一个巨大的三四百兆字节的二进制文件,这个文件并不与标准的 Sun 窗口应用程序(“tools”)共享空间。
这意味着,与其说窗口系统运行时只占用一个庞大的共享对象代码块,并占据我的交换空间,不如说我有了两个这样庞大的代码块,除了几页代码之外几乎完全相同。
所以,为了能够用鼠标操作编辑器,我额外支付了一个兆字节的交换空间。(Emacs 本身又是第三个庞大的代码块。)
Sun 内核显然快要没空间了。你对窗口系统做的每一个微小修改,都会复制整个窗口系统。
但此非全部:显然还有其他占用大量交换空间的庞然大物。某些网络程序的数据段异常巨大,而且随着时间推移会不断增长,最终我猜会塞满整个交换空间。所以你没法让 Sun 机器长时间开机。这也是我很庆幸 Sun 机器启动很方便的原因!
但为什么网络服务器的内存占用会随着时间增长?你必须知道,Sun 软件会动态分配非常复杂的数据结构。你应该对每个分配的结构调用“free”,但程序员的疏忽和冷漠使得一些垃圾数据不可避免地残留。最终交换空间就被塞满了!
这让我开始幻想一种工作站架构,专门优化用于创建和操作大型、复杂、相互关联的数据结构,同时有某种魔法般的机制能在无需程序员干预的情况下自动释放存储。这样的工作站可以连续运行数天,自动回收垃圾,不必频繁重启。
但当然,Sun 机器非常擅长启动!它们甚至有时会自发重启,让你知道它们处于巅峰状态!
控制台刚又抱怨内存不足。
天哪,我都没空谈论过去一周里那些我不用操心的 LispM 功能了。比如增量重编译和加载,或者从 Lisp Listener 进行程序的增量测试。或者一款你真正可以教会新东西的窗口系统(我怀念那个对鼠标敏感的 Lisp 窗体)。或者严格区分指针和整数的安全标签架构。或者 Control-Meta-Suspend 键。或者手册。
是时候重启了!
John Rose 给公司内部邮件列表发了封邮件。不知怎么的,这封邮件被转发给了媒体实验室的 Michael Travers。John 并不知道 Michael 会为他自己和其他痛恨 Unix 的朋友创建一个邮件列表并发出邮件。但 Michael 做了,而且七年后,John 仍然在 Unix 痛恨者邮件列表上,和其他数百人一起。
在那场火爆讨论的末尾,John Rose 加了这样一段免责声明:
【说真的,朋友们:我正在尽力从这台机器上榨取价值,上述某些问题是有解决办法的。特别感谢 Bill 为我增加了交换空间。从原始 CPU 性能来看,Sun 机器确实能快速完成任务。但我需要发泄一下,因为这个“编辑器突然消失”的状况真的让我火大。】
这算什么免责声明。相关公司买 Unix 工作站是为了省钱,但他们在硬件成本上节省的很快就被支持费用和程序员生产力损失的更高开销远远抵消了。不幸的是,现在我们知道了,却已经太晚。Lisp 机器在公司里成为了渐行渐远的回忆:每个人都用 Unix。大多数人认为 Unix 是个不错的操作系统,毕竟它比 DOS 好。
或者真是这样吗?
如果你用过 Unix 系统,你大概经历过我们和别人听说过的那些噩梦。你可能删除了重要文件,求助时却被告知是你自己的错,或者更坏,还被说成是“成长的必经之路”。你可能花了几个小时写给朋友的催人泪下的信件,却因邮件服务器出错丢失,或者更糟,发给了别人。我们的目的就是告诉你,你并不是一个人,你遇到的 Unix 问题不是你的错。