代碼極簡主義:初代windows任務管理器80KB背後的極致優化 | 中文配音

深度大乱斗
6粉絲
2026年8月30日
大家好,我是大夫。
歡迎來到我的小店。
我想坦白一個有點尷尬的事實。
最初的任務管理器,
是由年輕時的我編寫的。
那時的我聰明得有點危險,
又因缺乏安全感而過度優化。
而且剛脫離爲一兆赫茲的
Commodore 64編寫遊戲沒幾年,
最後這點很關鍵。
因爲如果你在成長機用的機器,
每條指令都得證明自己存在的價值。
就像申請貸款一樣,
你永遠無法完全恢復。
你不再把軟件看作由抽象概念
構成的柔軟蓬鬆之物,
而是開始覺得它有重量,
有質量,拖累和摩擦。
每行代碼都有代價,
每個分配都留下痕跡,
每個依賴項都像是個白吃白住
從不付租的室友。
所以當我編寫任務管理器時,
我沒有現代工具的方式,
從框架開始,
加上九層舒適性,
六層未來保障,
然後驚訝地發現,
這東西需要八百兆內存
和一番激勵演講
才能顯示幾個數字。
我像剛適應6502
稀缺環境的人那樣處理它。
如今,Windows上的任務管理器
大約四兆,
但我最初的文本不到80K,
這不是爲了參加什麼苦行僧比賽,
當然也不是預見到
將來需要個好故事上YouTube,
因爲在那個時代,
小巧意味着快速,
而快速至關重要。
任務管理器
是那種在系統已經出問題時
纔會調用的程序,
當系統感覺不對勁,
應用卡死,
機器喘不過氣的時候,
任務管理器可不能姍姍來遲,
被自己的依賴像壓得步履蹣跚,
必須立刻響應,
感覺乾脆,
即使系統混亂,
它也要顯得從容。
任務管理器得像維克多一樣出場,
永遠穿着最好的禮服。
任務管理器,
解決問題。
好,
有任務,
聽說了,
能進嗎?
我最喜歡的一點偏執設計,
就體現在啓動時,
多數人以爲按熱鍵時,
系統只是檢查任務管理器是否已在運行,
如果有,
就激活它,
但這還不夠,
因爲現有的實例本身,
可能已經卡死,
僵住,
或者出了別的毛病。
對於一個職責是診斷卡死問題的程序來說,
這可就太尷尬了,
所以新副本不會僅僅因爲存在一個窗口,
就假定舊實例還活着,
實際上,
它會發送私有消息詢問,
等待合理回覆後,
才移交焦點並退出。
換句話說,
任務管理器做的第一件事,
就是拒絕被表象欺騙,
有趣的是,
這就像是整個程序哲學的縮影,
別做顯而易見的事,
要做那些在顯而易見的方法失效時依然管用的事,
這種對啓動速度的執着,
也解釋了我代碼裏更瘋狂的事。
任務管理器,
基本不用吹ERT,
對普通人來說,
C運行時就像行李員,
幫C程序整理好再出門,
但年輕的我看着啓動負擔,
決定自己扛行李,
於是就有了自定義模塊入口,
手動便利K的使畫表,
以及對任何沒有充分體現價值的字節,
都保持深度懷疑的態度。
這是隻有年輕人才會覺得,
手動替換運行時啓動代碼,
是一個合理的下午活動,
但這確實換來了更小的二進制文件,
和更快的啓動速度,
那時對我而言,
快速啓動不是錦上添花,
而是全部意義,
這種對冗餘的警惕,
便即支持代碼,
我不用任何笨重的框架機制,
一個輕量級專門構建的結構就足夠了,
有一個自制的指針豎着,
用簡單的堆起髮式方法增長,
而不是引入龐大的集合庫,
頻繁使用的字符串,
只下載一次到全局變量中,
而不是需要時反覆獲取,
而不常用的功能,
只有在實際需要時才加載,
像彈出已連接PC這種冷門功能,
我不希望啓動路徑爲Moment Manager32買單,
買單,哪怕它偶爾可能被調用,
這背後藏着一個絕妙的古老工程原則,
不常用的代碼,其成本也應該很低,
對於極少使用的功能,
我會動態連接,不放進基礎代碼裏,
和上次一樣,
我並不是說現在工程師很笨,
他們並不笨,
他們現在的世界要複雜得多,
安全性更難保障,
無障礙功能更成熟,
國際化也很重要,
威脅模型也更棘手,
但現在,
我們常爲所有用戶預先支付全部成本,
不管他們是否受益,
像任務管理器這樣的老代碼則相反,
核心路徑不容累贅,
看進程頁,
它能如此廉價快速地刷新的原因之一是,
它不會通過便利系統,
進行大量小型API調用逐個進程詢問來重建進程狀態,
這就像試圖通過挨家挨戶敲門,
然後向每戶人家詢問三個不同的後續問題來做人口普查,
相反,任務管理器一次性向內核請求整個進程表,
如果緩衝區太小,就擴大緩衝區重試,
舉道成功,
這意味着只需跨越一次用戶內核邊境,
獲得更一致的快證,
並且在刷新列表時產生的動盪要少得多,
這種優化看似平常,
但想想用低效方式實現,
會讓普通電腦的界面卡頓遲緩,
一旦我拿到進程表,
我仍然不想浪費任何工作,
所以CPU百分比是分兩步計算的,
首先,任務管理器便利進程數據,
彙總所有進程的總時間增量,
然後在第二步,
每個進程根據這個共享的分母計算自己的百分比,
這聽起來是細節,
但很重要,
原因有二,
首先,
它避免了爲每一行反覆重新計算分母,
節省了一些工作,
第二,
它保持了百分比內部一致,
第一行和第87行所依據的基準是相同的,
每個人都用同一顆時鐘來評判,
這種細節用戶不會特意注意,
但一旦出錯,
他們立刻能察覺,
數字跳動不一致或可疑,
會慢慢消磨用戶對工具的信任,
接着是我最喜歡的一個小而精的優化細節,
每個進程行都有一個32位的緊湊三位聯合體,
專門記錄具體哪系列發生了變化,
不是問這一行有沒有變化,
而是問具體變了什麼,
CPU變了嗎?
GPU數據變了就標記,
工作機變了就標記內存,
劇頂數沒變就不動,
這很苛刻,
但列表重會有成本,
90年代硬件上閃爍影響體,
閃爍意味着你在EY線程上乾的蠢事,
所以任務管理器會逐字段比對,
除非某個單元格真有新內容要說,
否則絕不喚醒顯示,
同樣的思路也延續到了報表仕途的同步方式上,
現代偷懶的做法是直接推平一切,
重建上色,
指望機器夠快,
沒人察覺,
而他先關閉所有重會,
通過穩定的對象,
指針匹配行,
指更新有變動的型,
及其內部單元格,
他只在尾部按需增刪,
他是增量同步,
而非戲劇性的重建,
與其重算列表,
不如更新至最新,
這道理該文在產品團隊身上,
同步而非清空,
更新而非重建,
尊重連續性,
保持持字性,
機器喜歡這樣,
用戶的眼睛也會喜歡,
那些列裏的文字,
也比看起來更矮,
這是誇獎,
子項字符串,
並非預先格式化好,
等着被調用,
他們是在列表通過
LV Get the Smurf Info請求時
才攬生成的,
這意味着
如果某行不在屏幕上,
或者某個子項
永遠不需要繪製,
就沒人會白白浪費週期
去格式化它,
對穩定字短,
任務管理器允許空間緩存,
這真是經典的老派操作,
別生產沒人要的字符串,
就像不會在早上八點
擺好所有餐盤等客人點單,
現在說閃爍問題,
年輕時的大夫對此很執着,
90年代,
閃爍會讓程序顯得廉價,
功能再全,
若窗口像哈哈鏡般刷新,
用戶就覺得卡頓,
任務管理器
做了大量防閃爍處理,
當時看來值得,
我認爲值得,
列表視圖也被子類化了,
因此背景擦除
只發生在項目本身未佔用的區域,
就像刷牆直刷看對鍵的部分,
如果沙發還擺在那兒,
就別重刷沙發後面的隱藏牆面,
正常的擦除和重繪行爲很浪費,
還會導致明顯的閃爍,
所以任務管理器
計算列表向佔用的可進區域,
從整個客戶區中減去它們,
只擦除需要擦除的部分,
這種優化成功了也沒人注意,
因爲這就是它的目的,
沒有明顯的變化發生,
小圖表容器也得到了類似處理,
有個叫大夫的框架窗口的自定義分組框,
就是爲了防止副窗口重繪並覆蓋此圖表,
裁剪銅集和紫元素,
別在活動空間底下亂刷背景,
總之別像個沒人監督
拿着滾筒刷的最恨粉刷工那樣行事,
這種代碼會讓年輕開發者覺得你古怪,
畢竟就爲消除閃爍做這麼多,
爲老硬件費心,
絕對缺的,至今仍是,
流暢從來不是小事,
它是延遲的直觀體現,
性能圖表本身是雙緩衝的,
也就是說它們先在屏幕外的內存中繪製,
然後一次性乾淨地複製到顯示屏上,
歷史數據存在緊湊字節數組裏,
不是給哲學系用的複雜對象圖,
每次計時只更新歷史並驗證圖表,
不刷新整驗,
如果窗口確實最小化了,
它會完全跳過重繪工作,
因爲精美繪製沒人能看到的像素可沒獎勵,
這可能是整個程序中最永恆的優化,
用戶得不到好處時就別幹活,
聽起來顯而易見,
但整整一大類現代軟件
似乎把這個理念丟在了某個搖測管道附近,
這種總體哲學不僅體現在繪製上,
任務管理器還有一個低內存模式,
現在少見,
但若機器資源極度緊張,
就只出史化前兩個標籤頁,
不要圖表,
不要附加功能,
只留幫你排查問題必須的東西,
這想法如今很不時髦,
甚至顯得激進,
也許軟件應該根據運行它的機器來調整自己的野心,
不是每個系統都需要大動干戈,
有時只需兩標籤,
一進城列表和運氣,
我對此特別有感情,
因爲它抓住了這段代碼的整體基調,
任務管理器最棒的可能不是任何可見功能,
而在於代碼一再拒絕自我膨脹,
它拒絕僅僅因爲有能力就去做工,
它不因存在而加債,
除非對用戶有明確好處,
否則它拒絕重匯,重骸或重算,
這和很多現代工具形成鮮明對比,
問題不在於它們體積大,
很多現代軟件有正當理由比老式桌面工具更大,
它們往往缺乏這種拒絕的本能,
它們不問用戶現在能受益嗎?
只問硬件能跑得動嗎?
這完全是兩回事,
一是尊重,
二是投機,
不美化這代碼,
在老任務管理器裏,
確實能看到年輕時的我在辦公室洋洋得意,
以爲自己聰明絕頂,
有些設計確實非常實用,
但也有些地方古怪的可愛,
有些做法只有還沒被生產事故教訓過的人才會這麼幹,
即便現在看有趣,
其嚴謹仍令人欽佩,
這代碼極力避免浪費機器資源,
這種價值觀本該被更多軟件奉爲歸頭,
因爲問題在於,
硬件性能的提升本該爲我們帶來便利,
它本該帶來及時響應,
豐富界面,
更安全系統,
優雅降級和精緻體驗,
可太多時候它只帶來了自滿,
我們把額外資源揮霍在從未評估成本的層級,
未經論證的服務,
以及那些放在90年代會被轟出會議室的常駐後臺活動上,
這不是進步,
只是臃腫患狀,
任務管理器理念不同,
它來自一個能切身感知缺頁錯誤,
能嗅到內存不足異樣的時代,
那時錯誤刷新頻繁,
隔壁同事都會哀號,
自然絕不想回到舊硬件時代,
但我希望我們保留了那種審美,
不是指那些痛苦,
而是那種品味,
批量處理的直覺,
緩存關鍵內容,
跳過無效工作,
重會淺顯比對,
向內核單次而非百次查詢,
喊用數據延遲加載,
對用戶買單的便利,
保持警惕的本能,
讓我保持清醒的是,
我仍在PTP11上編程,
它的速度和初代IBM PC相當,
每次只能使用64K內存,
磁盤操作脈如地質演變,
重新編譯,
最好趁午餐時間進行,
這套技能至今仍適用,
儘管硬件早已過時,
如果說這段歷史對現代團隊有何啓示,
絕不是用原生Win32重寫,
借並向瘋子般手動便利CT表,
請別誤解重點,
真正的啓示更簡單使用,
追蹤時間與數據的續想,
關注啓動與空閒,
要周視UI現成,
重繪格式處理都是正經工作,
分配即工作,
抽象即工作,
硬件是快了,
但浪費並不高尚,
它只是讓浪費更難被察覺,
直到堆積成需要更新服務,
極皮優和成器,
只爲告知進程佔12%CP優,
也許這就是任務管理器至今仍好用的原因,
不是因爲它完美,
天知道它不完美,
而是因爲它懂規矩,
該說時說,
說完即退,
它用種嚴厲的小效率幹活,
這更多出於必要,
而非天賦,
我從未試圖建造鳳輩,
我只是不想在慢到無法掩蓋錯誤的機器上,
被抓到浪費時鐘週期,
說實話,
這倒是個學習編程的好方法,
如果你喜歡本期內容,
別忘了我的動力,
主要來自訂閱和點贊,
離開前請三連支持,
已訂閱的朋友,
感謝!
字幕由Amara.org社區提供
