阿波罗11号登月源码竟然开源了!仅靠4KB内存,把人类送上月球!
吐槽解读
50 多年过去,千亿参数大模型当道,我们却仍会为一份 4KB 内存里写出的登月代码起鸡皮疙瘩——因为它把「在极限约束下把事做成」做到了极致。
本文从基础结构、内存与储存、虚拟机、软重启一直拆到彩蛋,逐层解读阿波罗导航计算机(AGC)的源码设计;文末附 GitHub 仓库与源码复原过程。

主张对照(本站解读)
| 维度 | 这篇文章 | 我们的判断 |
|---|---|---|
| 主角 | AGC 登月源码(1969) | 50 年前的汇编,今天仍被膜拜 |
| 硬核点 | 4KB 内存多任务 + 磁芯绳存储 | 匮乏逼出了极致的优雅 |
| 动手建议 | 去 GitHub 翻 chrislgarry/Apollo-11 | 顺手点个 Star,致敬那群年轻人 |
真是螺蛳壳里做道场,太强了…
Programmers 2020 vs Programmers 1960s(2020 年的程序员 vs 1960 年代的程序员):
“Help me pliz, I can’t exit vim.”(救救我,我退不出 vim 了)
“With this software we shall fly to the moon and back.”(用这套软件我们就能来回飞往月球)
—— stackoverflow
(原图为一张对比梗图:讽刺今天程序员被“退不出 vim”困住,而 1960 年代的程序员却用同样的工具写出了把人送上月的代码。)
仓库名叫 chrislgarry/Apollo-11,截至 2026 年,已经有 7.5 万个 Star。
仓库链接:
https://github.com/chrislgarry/Apollo-11
于是,我把这个仓库又又又从头到尾翻了一遍,发现了很多有意思的细节。
一、代码基础结构
仓库里有两套核心程序:负责指令舱的 Comanche055(Colossus 2A),和负责“鹰号”登月舱的 Luminary099(Luminary 1A)。
| 维度 | 要点 |
|---|---|
| 运行内存 | 仅 4 KB,却要跑完整个导航与飞控程序 |
| 储存 | 约 72 KB 磁芯绳只读存储器,铜线手工穿织、定稿即不可改 |
| 基础结构 | EXECUTIVE 任务调度 + WAITLIST 定时任务 + 中断处理 + 重启恢复 |
| 省内存 | 同一块内存按飞行阶段轮流用,登月舱程序标注了 1500 个变量的归属 |
| 多任务 | 8 个任务槽各 12 个字,另加 5 块 44 字草稿区,整套只占约 340 个字 |
| 虚拟机 | 7 位操作码一个字塞两条指令,用正负号省掉地址,撑起 28 位双精度 |
| 软重启 | 下降途中报警 5 次(多为 1202),靠断点记录把关键任务重新拉起 |
| 彩蛋 | 主点火程序名为 BURN_BABY_BURN,注释里写满人味 |
程序各约 6.5 万行(含注释),各有 90 个左右的文件,全部平铺在一个目录里,没有子文件夹。
它本质上是从头到尾一次性汇编,不像现代项目那样拆成独立模块。
(题图:GitHub 仓库 chrislgarry/Apollo-11 页面截图——75.6k Star、8.2k Fork、588 Commits,话题标签含 agc / apollo / nasa / hacktoberfest。)
-
底层是操作系统: EXECUTIVE(任务调度)、WAITLIST(定时任务)、中断处理、重启恢复。 -
中间层是公共能力: INTERPRETER(虚拟机)、各种数学子程序、PINBALL_GAME_BUTTONS_AND_LIGHTS(键盘和显示)。 -
上层是具体任务,文件直接按程序编号命名,比如 P20-P25、P40-P47、P51-P53。这些编号和宇航员在键盘上输入的程序号是一一对应的,P63 就是登月下降。
看起来平平无奇,实则每一层的设计都非常精妙,我们逐个拆解这套代码的关键设计,你就会理解 4KB内存是怎么把人送上月球的。
二、极限内存和储存
KB运行内存,72 KB 储存登月,怎么做到的?
首先了解一下他们用的计算机,是阿波罗导航计算机。
这台计算机重约 32 千克,功耗仅 55 瓦,主频约 2.048 MHz,是最早采用集成电路的计算机之一。

今天的电脑和手机普遍数据按 8 位一个字节来存。
而 AGC 一个字只有 15 位数据,外加 1 位用来查错的奇偶校验位,连“字节”这个概念都没有。
也没有浮点数,程序员只能自己记住每个数的小数点在哪。

阿波罗机载飞行软件团队负责人玛格丽特·汉密尔顿
所以,在这样一台机器上写登月程序,其实是非常困难的。
我翻了专门分配内存的 ERASABLE_ASSIGNMENTS.agc 和调度程序 EXECUTIVE.agc,发现 60 年代的程序员为了把这点内存用到极致,想了两个办法:
第一,同一块内存按阶段轮流用。
翻到这个文件的开头可以发现,他们给大量内存位置标了“身份”。
PRM 表示整个任务期间专用;TMP 表示可以临时借用,不同时运行的程序能共用同一块。

光是登月舱程序,就标注了 1500 个变量。
而且每个变量还有不同注释,写明它可以和谁共用,不能和谁共用。
比如有的写着“可以覆盖,但要小心,只在动力下降时使用”,有的写着“不能覆盖 RONE 和 VONE”。

第二,每个任务只给 12 个字的空间。
登月过程中,计算机要同时做好几个任务,比如导航计算、发动机控制、姿态调整。
但它不会临时给任务分配内存,而是提前切好 8 个“任务槽”。
每个槽 12 个字,相当于一个极简的进程上下文。
当前任务固定在 0 号槽,切换任务只需交换两个槽的 12 个字。

要做向量、矩阵这类复杂运算的任务,还能再领一块 44 个字的“草稿区”。
但一共只有 5 块,用不着的任务一个字都不多给。
算下来,整套多任务系统只占了大约 340 个字,用六分之一的内存,就能让这台计算机实现多任务调度。

而 72KB的储存则更硬核,是用铜线织出来的。
那时候没有闪存芯片,大家的选择不多,只能选择磁芯绳存储器。
这是一种纯手工制作的存储器。甚至没有通电写入这个功能,数据就是它的物理结构本身。
代码定稿后,会被送到工厂。
由女工们坐在放大镜前,拿着细细的铜线,对着一排排微小的磁环穿针引线,铜线从磁环中间穿过代表 1,从旁边绕过代表 0,这样储存一整套登月程序。
(图:RAYTHEON——阿波罗导航计算机 AGC 的制造商雷神公司。)
女工穿线
铜绳一旦织好,就再也改不了,更没法在线打补丁。所以,代码结构必须万分严谨,不能有冗余。
翻开 FIXED_FIXED_CONSTANT_POOL.agc,能看到代码中刻意去重的地方。
有不少常数直接引用别处已有的位置,比如说数字 4、数字 11,都可以借用键盘显示程序里现成的存储单元。

更有意思的是,常数的相邻关系也被利用了,负零放在零前面,两个字连起来,又能作为一个双精度常数使用。

而最大的一笔减法,是在这台机器里被塞进了一台“虚拟机”。
二、波兰虚拟机
翻开 INTERPRETER.agc 文件,会发现一个更疯狂的设计。
前面说到的阿波罗导航计算机,它天生只认识 8 条基本指令,甚至无法直接进行向量和矩阵运算,连乘除法都要借助额外的前缀指令才能完成。
但是,我们必须要让它算出三维空间里的登月轨道,怎么办?
(图注:阿波罗登月轨道示意·非等比例。)
在这样的硬件条件之上,60年代的程序员硬生生用汇编写出了一套解释器。
按源码粗略估算,它只占了约 2000 个字的程序存储,却能直接处理 28 位的双精度数,以及由 6 个字组成的三维向量。
只要在汇编里写一行 TC INTPRET,这台 15 位的机器就会切换进虚拟机模式,点乘(DOT)、叉乘(VXV)、单位化(UNIT)、矩阵乘向量(MXV),都只要一条指令。

为了省空间,这台虚拟机也处处精打细算。
虚拟机省空间妙招:
① 一个字塞两条指令——操作码仅 7 位,最多编 128 种运算;汇编器把相邻的两条打包进同一个 15 位字,指令部分的空间直接省下一半;
② 用正负号省掉地址——虚拟机采用不需要括号的波兰表示法,操作码字存储时被取反(负数),内存地址则是正数;需要取操作数时它先“偷看”下一个字:是正数就去那个地址取数,是负数说明程序员没写地址、下一个字已是新指令,直接从结果栈弹出上一步结果接着算。
一是一个字塞两条指令。
虚拟机的操作码只有 7 位,最多能编 128 种运算。
汇编器会把相邻的两条打包进同一个 15 位的字里,指令部分的空间直接省下一半。
二是用正负号省掉地址。
虚拟机采用不需要括号的波兰表示法,操作码字存储时被取反,是负数;内存地址则是正数。
需要取操作数时,它会先偷看下一个字。
是正数,就去那个地址取数;是负数,说明程序员没写地址,下一个字已经是新指令了。
它就直接从栈里弹出上一步的结果,接着算。
三、软重启机制
还有一部分值得说,就是藏在 RESTART_TABLES.agc 里的软重启机制。
1969 年 7 月 20 日,“鹰号”登月舱下降途中,发生了惊心动魄的一幕。
离月面还有约 1 万米时,计算机突然报警。

阿波罗登月器导航计算机专家杰克:加尔曼在发射前模拟导致着陆中止后,编写了一份备忘单,列出了警报代码。史蒂夫·贝尔斯在阿波罗11号登陆时将这份副本贴在他的控制台上。
警报一共响了 5 次,大部分是 1202,中间还夹着一次 1201。
OCT 1201 # NO VAC AREAS.
OCT 1202 # NO CORE SETS AVAILABLE.
1202 是“任务槽用完了”,1201 是“草稿区用完了”。
前面说的那 8 个任务槽、5 块草稿区,在登月最关键的时刻被挤满了。
换成很多计算机,这时候大概已经死机了。
但阿波罗计算机很快就恢复了工作,导航和发动机控制几乎没受影响,这全部归功于程序设计的软重启机制。

它的思路很简单:关键任务每走到一个重要步骤,都会调用一次 PHASCHNG,记下“我是第几组任务、走到了第几步”。
这些断点都保存在内存里,重启也不会丢。
一旦撑不住,计算机就进入报警程序 BAILOUT,记下报警代码,再跳到软重启入口 ENEMA。
把堵住的任务一口气清空,再按断点记录,把导航、发动机控制这些关键任务重新拉起来。
飞船就这样在一次次重启中,继续稳稳地往下降。
四、程序彩蛋
翻到注释里,你会发现这群 60 年代的程序员其实非常好玩。
登月舱的主点火程序,文件名叫 BURN_BABY_BURN–MASTER_IGNITION_ROUTINE.agc,直译过来就是“燃烧吧宝贝燃烧,主点火程序”。
这句话来自 60 年代的灵魂乐 DJ Magnificent Montague,他每次播到最火的新歌,都会大喊一句“Burn, baby! BURN!”,写点火程序的 Don Eyles 和 Peter Adler 就顺手借来当了名字。
(图中文字:7:10 A.M. – Magnificent Montague。Magnificent Montague 是 1960 年代灵魂乐 DJ,“Burn, baby! BURN!”这句口号即出自他,被主点火程序作者 Don Eyles 和 Peter Adler 借去当了文件名。)
点火参数表上方还写着一句 NOLI SE TANGERE,化用《圣经》里的“不要碰我”,意思是这张表谁也别乱动。
登月程序 THE_LUNAR_LANDING.agc 里的注释更逗。
计算机提示宇航员手动转动雷达天线时,注释写着“PLEASE CRANK THE SILLY THING AROUND”(请把这破玩意儿转过来)。
宇航员按了确认,它还要再查一遍,注释写着“SEE IF HE’S LYING”(看看他是不是在骗人)。
确认无误后,程序跳转去点火,注释则写着“OFF TO SEE THE WIZARD…”(去见魔法师了),化用的是电影《绿野仙踪》里的经典歌名。

有意思的是,全篇搜不到一个 TODO 或 FIXME,可能因为在登月这件事上,没人敢把问题留到以后。
最后说说这份代码是怎么来的。
它不是 NASA 从哪块硬盘里导出来的,而是一摞存放在 MIT 博物馆里的纸质打印稿。
翻开任意一个文件的开头,都能看到这样一段说明:
Apollo-11/Luminary099/RESTART_TABLES.agc # Copyright: Public domain. # Filename: RESTART_TABLES.agc # Purpose: Part of the source code for Luminary 1A build e99, # for the Lunar Module’s (LM) Apollo Guidance Computer (AGC), Apollo 11. # Assembler: yaYUL # Contact: Ron Burkey <info@sandroid.org> # Website: ww.ibiblio.org/apollo # Pages: 238-243 # Mod history: Assemble revision 001 of AGC program LMY99 by NASA 2021112-061, 16:27 JULY 14, 1969
代码由飞行历史学者 Paul Fjeld 在博物馆逐页拍照,由博物馆的 Deborah Douglas 协助安排,再由 Virtual AGC 项目的 Ron Burkey 带着志愿者,对着照片一个字符一个字符敲回电脑,最后用汇编器 yaYUL 重新编译验证。
登月舱程序的打印稿上,还印着当年的汇编时间:1969 年 7 月 14 日 16 点 27 分。
也就是说,这份代码定稿时,离阿波罗 11 号发射只剩两天。
五、结尾
chrislgarry/Apollo-11 这个仓库,每隔几年就会被新一代程序员重新翻出来膜拜。
为什么在拥有千亿参数大模型、几十 GB 内存手机的今天,我们看着五十多年前的八进制汇编,依然会起一身鸡皮疙瘩?
因为极度的匮乏,逼出了极致的优雅。
今天的我们太富有了。内存不够?加内存条。
代码跑得慢?升级显卡。
有 Bug?先上线,等用户报错了再打补丁。
我们在海量算力的温床里,写出了越来越臃肿、越来越脆弱的软件。
而打开阿波罗 11 号的源码,你会看到另一个世界。
在那个只有 4 KB 内存、连改一行代码都要剪断铜线的年代,一群平均年龄二十多岁的年轻人,在针尖上跳出了一支零失误的芭蕾。
在这堆发黄的汇编指令背后,是人类在算力荒原上,仅凭智慧、纪律与勇气,向星辰大海递出的第一封信。
- 阿波罗11号登月源码已在 GitHub 开源,仅靠 4KB 运行内存与 72KB 磁芯绳存储,1969 年的工程师用汇编写出了整套飞控系统,本文逐层拆解其设计。
- 登月代码为何至今被膜拜?4KB 内存里跑出多任务调度,铜线手工织就的储存不可改写,匮乏的环境逼出了极致的优雅与纪律。
- 阿波罗导航计算机 AGC 的源码开源在即:从 Comanche055 与 Luminary099 两套程序,看 60 年代程序员如何用汇编算出登月轨道。
- 一份 1969 年的八进制汇编,今天仍有程序员翻出来学习。本文拆解其任务槽、草稿区、虚拟机与软重启机制,看 4KB 怎么够用。
- 磁芯绳存储器用铜线穿过磁环代表 1、绕过代表 0,数据即物理结构;虚拟机用波兰表示法在 15 位机器上跑 28 位双精度——登月代码的巧思尽在其中。
- 阿波罗源码彩蛋满满:主点火程序名叫 BURN_BABY_BURN,注释里写着 PLEASE CRANK THE SILLY THING AROUND,全篇找不到一个 TODO。
- 4KB 运行内存、72KB 储存如何撑起登月?同一块内存按阶段轮流用,8 个任务槽各 12 个字,整套多任务只占约 340 个字。
- 1969 年登月舱下降途中计算机五次报警,却没坠毁——全靠软重启机制按断点恢复导航与发动机控制,继续稳稳下降。
- chrislgarry/Apollo-11 这份代码来自 MIT 博物馆的纸质打印稿,由志愿者对着照片逐字敲回电脑,再用汇编器重新编译验证。
- 极度的匮乏逼出极致的优雅:在 4KB 内存、连改一行代码都要剪断铜线的年代,一群二十多岁的年轻人跳出了零失误的芭蕾。







都是华为的专利
月薪3000的日子很苦吧?
教教我怎么串吧
串和输都有赢法🤣
遥遥领先
回复 萤与火LY:厉害了我的为
优雅
2015年时候看优酷鸿观,宋鸿兵把半导体行业几十年的底层逻辑总结的相当到位。意思就是既然硬件性能每18月翻一翻,程序员根本不需要去优化程序,反正硬件越来越强,程序优化来干啥,最后都能跑动。就造成了一个现象软件根本不进步,反正硬件进步。
有个解释不通的事,既然整个系统都是以KB计,那说明当时的计算能力和存储水平极度有限。怎么做到的登月直播?那可是视频流啊
直播又不是数字化的
没电脑之前,人类不看电视?
同感,2010年坦克世界用的是winxp,cpu双核双线程奔腾,内存4gb,只有机械硬盘。只要有个好点的显卡就能画质跟今天没啥区别,一样流畅。到2025年win10,同样的内容,画质差不多,cpui7 8086k 6核12线程,内存16gb,显卡从450s 2g到5060 8g,没有固态都吃力。实际体验操作还是那些,反而更不自然。硬件开销大了没十倍都有5倍。同样word2003年xp 128mb内存就够了。现在win11 16g都够呛。同样干写字,硬件性能翻了上百倍,实际体验干的活本质上一样,反而越来越卡。越来越不自然。
因为不做优化了,靠蛮力了
回复 AAA花姐乐子批发:想想QQ以前多大?同样是聊天。现在多大?都上G了,一大堆花里胡哨的东西往里面塞,啥用都没。我就只想用一个纯粹的聊天工具而已。
游戏画质区别还是很大的。
回复 区钢浩:因为招了人,招了人就得做事情,那就证明自己做了多少工作的最好办法就是把各种乱七八糟的东西全都往软件里面加毕竟汇报的时候说加了哪个新功能比优化了一点流畅度直观的多也省力得多
虽然最早写的是C(2012年),部分高要求的功能才内嵌一点汇编。但不得不说那时候一点点地扣空间算性能,权衡复杂度算一笔笔账,写出来东西真的超爽。恨不得把所有地方做到极致
时不时还能上论坛讨论一下彼此觉得”优雅”的代码
美国登月骗局罢了,这代码都不知道有没有真跑起来。
众人独醉我独醒
是的,另外英语课也应该全面取消
回看现在的软件,都像狗屎
TO DO
上学就讨厌汇编语言 太难了!
极度的匮乏,逼出了极致的优雅。这句话真的太赞了。
真的是鸡皮疙瘩都起来了!
最疯狂的年代,做出了最疯狂的事,致敬阿波罗计划~