來源:量子位
折磨全球無數 GTA 5 玩家的聯機版超長加載時間問題,終于要修復了。
什么?R 星主動改善玩家游戲體驗?不存在的。
打開 GTA 5 聯機版,要跑 19.8 億次 if 語句,一支煙的功夫游戲都加載不完。這堪稱游戲開發史上最大的 " 屎山 " 代碼,存在了 7 年,R 星從沒想過要修復……
玩家對 GTA 5 聯機版可謂又愛又恨,有人甚至破口大罵:
直到一位黑客大哥路過,實在忍不了惡臭的代碼,嘲諷完 R 星后,隨手按了 " 沖水鍵 ",直接將等待時間壓縮 70%。
鑒于 R 星失誤實在太低級太離譜,而這位老哥的方法又太有效,以致無數玩家稱他 " 功德無量 "。
如果平均給每個玩家節省 10 秒,全球 500 萬玩家一天就能節約 5000 萬秒,一年中,節約的總時間大概能有數十年。相當于挽救了十多個人的生命!
R 星這才坐不住了,趕忙官宣修復 bug,不但采用了黑客的方案,還大方的給他獎勵了 1 萬美元 " 賞金 "。
黑客 " 治病救人 "
不久前,量子位曾經介紹過黑客大哥通過逆編譯器檢查 GTA 5,并且重寫代碼,一下節約 70% 加載時間的故事。
先來前情回顧一下。
簡單地說,就是 GTA 5 聯機版加載時間長得過分,有超過 80% 的玩家要等 3 分鐘以上,有的人甚至要等 15~20 分鐘。
一位黑客大哥實在忍不了,于是決定開扒 GTA 5 的代碼,看看到底是哪里出了問題。
首先,他用 Windows 任務管理器,來判斷聯機版 GTA 5 在啟動時,都調用了哪些計算機資源。
在 1 分鐘的時間分界線上,之前是加載的是單機和聯機版通用的基礎內容,之后是聯機版獨有的內容。
可以看到,聯機版 GTA 5,加載時調用大量 CPU 資源至少長達 4 分鐘之久,而同時,內存、GPU、硬盤的使用情況幾乎沒有明顯變化。
所以,問題大概率出在代碼上。
黑客大哥說:
我聞到一股爛代碼的味道……
為了找出到底那一部分程序卡住了 CPU,他使用了工具 Luke Stackwalker,對 CPU 任務堆棧進行采樣分析。
沿著調用棧往下走,發現問題出在一個 sscanf 函數上。
sscanf 的功能是讀取格式化的字符串中的數據,而在 GTA 5 中,它正在讀取的是一個 10M 左右,有 63000 多個條目的 JSON 文件。
這個文件到底是干什么用的?黑客大哥推測,這可能是游戲內購商店的相關內容。
再看第二個問題,這是一個存儲命令,對象是 item,具體是什么不得而知。
但是保存前,有一個 if 語句,逐一比較 item 內項目的哈希值,檢查它們是否出現在某一列表中。
按照他計算,這一步 if,要執行(63000^2+63000)/2 = 1984531500 次!
沒錯,等待加載前的十多分鐘里,GTA 5 用你的 CPU,執行了 19.8 億次 if 命令。
如此簡單粗暴的編程思路,讓這位老哥哭笑不得:
既然對象有唯一哈希值,那為什么不用 hash map?
至于 R 星為什么不修正,有網友推測,最開始,if 的循環次數并沒有這么多,而是隨著開發,條目不斷增多,最后到了積重難返的地步。
而之前的代碼結構,誰也不愿意去動。
就是這樣一個低級的失誤,讓全球玩家至今每次打開游戲,都要上演一遍 19.8 億次的 if 循環……
這是不是堪稱游戲開發史上最意外的 " 屎山 " 代碼?
如何沖掉 " 屎山 "
第一個問題,黑客大哥采用 hook 大法,不一一讀取字符串,而是:
hook strlen" 緩存 " 字符串起始和當前長度。如果在字符串范圍內函數在此被調用,返回緩存的值。
至于 if 語句問題,就更直接了—