微軟說,
Visual Studio 在具有 64 GB RAM 的 Windows 11 和具有 16 個核心或更高版本的 CPU 上執行最佳。它執行速度更快,並且比同一硬體上的 Visual Studio 2022 響應更快。
官方的解釋是,這是為了方便開發者有理由向公司爭取到更好的硬體。
我這臺裝置是工控機,4 GB 的記憶體,處理器則是 2020 年的賽揚 N5095,效能比綠鏢上的還差些,只有 4 核。因此,這是推薦配置的 。自然,不用再乘上 ,因為後者反而更像是負最佳化——而且也確實是的,因為這臺機器看起來比我的筆記本更不拖泥帶水。
這個裝置定期讀取串列埠,測量資料,然後顯示在介面裡。我的主要任務是修復這個裝置上專用的陳年 MFC 程式無法長時間執行的問題。 具體來說,在兩三天後,程式會先彈出一個有程式名稱的、空白的、MsgBox 大小的窗體,然後點確定就會 crash。一看到這個問題,我就想是記憶體洩露,雖然這麼說可能是 hindsight。
程式碼自然是 GBK 的,甚至沒有 formatter
的痕跡。我檢查了一遍程式碼,沒有任何在異常時彈窗的程式碼,即這個彈窗是 MFC 自己畫的。程式碼中使用了
Windows 的臨界區 CRITICAL_SECTION,是 Windows 的使用者態 mutex,不過這些部分都沒什麼問題。讓
Claude 審了幾遍,只查出來幾個無關痛癢的問題,比如判斷 sleep 的 int
可能會溢位,但這個只會導致某一輪測量的間隔縮短。
x32dbg 除錯
這個程式需要讀串列埠,還用了廠家提供的 .h + 閉源 .dll,因此我需要在生產環境中除錯。
由於一開始實在是不想折騰開發環境,於是我在現場環境中,先是安裝了 x32dbg
企圖找到點什麼線索。然後成功捕獲到一次異常。異常發生時,偵錯程式停在了
RaiseException 和 _CxxThrowException 上,同時還有
ERROR_NOT_ENOUGH_MEMORY 和 STATUS_NO_MEMORY。這說明程式是在某次記憶體分配失敗之後,透過 C++ 異常機制被拋了出來。
- 工作集(記憶體):5,324 K
- 峰值工作集:753,552 K
- 提交大小:1,857,512 K
32 位程序預設使用者態地址空間通常只有 2GB,Commit size 1.77GB 對 32 位程序來說很危險了。
Registers
暫存器狀態轉儲中,關鍵的是:
...
EIP : 75670F62 kernelbase.75670F62
EFLAGS : 00000212
...
EBP : 07ECBA3C
ESP : 07ECB9E0
...
LastError : 00000008 (ERROR_NOT_ENOUGH_MEMORY)
LastStatus : C0000017 (STATUS_NO_MEMORY)
...
Log
執行緒 1596 已建立,入口:wer.6C853F70,引數:2DB43178
執行緒 1596 退出
EXCEPTION_DEBUG_INFO:
dwFirstChance: 1
ExceptionCode: E06D7363 (CPP_EH_EXCEPTION)
ExceptionFlags: 00000001
ExceptionAddress: kernelbase.75670F62
NumberParameters: 3
ExceptionInformation[00]: 19930520
ExceptionInformation[01]: 07ECBA84
ExceptionInformation[02]: mscorwks.6FA04588
第一次異常於 75670F62 (E06D7363, CPP_EH_EXCEPTION)!
Call Stack
棧回溯中可以看到——
執行緒 ID 地址 返回到 返回自 大小 方 註釋
2528
07ECBA40 74BA8E89 75670F62 38 系統模組 kernelbase.RaiseException+62
07ECBA78 6F7C7550 74BA8E89 50 系統模組 msvcr80._CxxThrowException+46
07ECBAC8 6F757C46 6F7C7550 30 系統模組 mscorwks.LogHelp_NoGuiOnAssert+24D
07ECBAF8 6F5BF2AE 6F757C46 68 系統模組 mscorwks.LogHelp_TerminateOnAssert+3F32
07ECBB60 76F46F5C 6F5BF2AE EC 系統模組 mscorwks.StrongNameErrorInfo+7DCA
07ECBC4C 6EFFB1EB 76F46F5C C4 系統模組 ntdll.RtlAllocateHeap+109C
07ECBD10 007D4987 6EFFB1EB 4 使用者模組 mscorlib.ni.6EFFB1EB
07ECBD14 007DE6EA 007D4987 4 使用者模組 [資料刪除]e.007D4987
07ECBD18 007DE6F4 007DE6EA 4 使用者模組 [資料刪除]e.007DE6EA
07ECBD1C 00000000 007DE6F4 使用者模組 [資料刪除]e.007DE6F4
604 - 主執行緒
006FF5BC 6FD1E53E 74D8106C 48 系統模組 win32u.NtUserGetMessage+C
006FF604 6FCFB9A4 6FD1E53E 4C 系統模組 mfc90u.Ordinal#1161+1A
006FF650 007D4578 6FCFB9A4 4B8 使用者模組 mfc90u.Ordinal#2208+12A
006FFB08 6FCEAEC6 007D4578 14 系統模組 [資料刪除]e.007D4578
棧裡出現了 mscorwks 和 mscorlib,看著像是 .NET CLR 參與了呼叫。主執行緒停在訊息迴圈中,說明 crash 並不是 UI 邏輯主動觸發。
配置開發環境
為了除錯和修復這個問題,我需要在工控機上配置一個開發環境。機上已經有一份
VS 2008,惟點開後提示已經過期。從網際網路檔案館上
VisualStudio2008_Collection
這個 item 裡下載了一份 Visual Studio 2008 Standard Edition。安裝的時候,為了節省空間,我只勾選了
C++ MFC 部分。然而,正是這個選擇讓我沒有辦法正常編譯程式——生成時會提示找不到
cl.exe。查詢了幾天,才發現是因為由於 bug 還要勾選 VC# 才能裝上:

StackOverflow 問題 error PRJ0003 : Error spawning 'cl.exe',CC BY-SA 2.5,有
Cloudflare CAPTHCA,不建議人類和 agent 訪問。
There is a bug in the Visual Studio 2008 Standard Edition installer. It does not install cl.exe if you only install Visual C++ but not Visual C#. To work around this you have to install Visual C# even if you do not need this.
查詢紕漏
在 VS 上裝了 wakatime 和 Github Copilot 擴充,雖然 Copilot 也不是很好用,沒有 agent 模式。如果想要 apply 變更,只能手動點 diff 上的按鈕,它的方法是讓 LLM 生成一個編輯好的版本(這個是和 VS Code 上的一致的)。不過,值得讚揚的是,其介面都使用了原生控制元件開發。
初步檢查了一遍程式碼,又發現了一些可能導致記憶體洩露的地方。
比如,IP 地址只給了個 char[13],正好夠存 "192.168.1.xx\n",多了都不行——配置是可以經使用者輸入改的。
改動後,我把程式的一些時間間隔之類的引數設定為很短的幾秒,這樣可以在正常呼叫裝置庫來 I/O 的情況下加快記憶體佔用的復現。但是,過程中經常會彈窗停住,似乎是錯誤地 drop 了某些 MFC 的資源,會在 Debug 下觸發內部的斷點,非常煩人——我並不想除錯這些可忽略的錯誤。 之後的兩三天都在嘗試避免這個問題。最後發現,將 target 的 Debug 改成 Release 即可,同時並不影響正常的記憶體監控。
記憶體快照
開始執行後,右側的 panel 裡可以開啟——,抓取快照,後面括號裡的內容是與上一個快照相比的 diff。如果是第一行會變成 (不可用),並不是抓取失敗的意思。
VS 這個診斷面板不知道是怎麼搞的,記憶體那個圖示在我點開後就會變成空白,但滑鼠忽上去還是有值。
罪魁禍首
這個 GetSpectrumData。
這個函式並沒有要求我們傳入一個 char*,所以其字串顯然是自行分配的,而我們每次將這個指標儲存,讀取解析後,在下一個迴圈又用新的返回值覆蓋了上一個指標而沒有 free。
跑了一週,不得問題。不過,彈出了一個 MsgBox,如下:
---------------------------
BackgroundDownload.exe - 應用程式錯誤
---------------------------
應用程式發生異常 未知的軟體異常 (0xe0434352),位置為 0x00007FFACC1EB699。
---------------------------
確定 取消
---------------------------
嚇我一跳,還以為又壞脫;查了查發現是 VS Installer 的問題。也許 VS 真的需要 64 GB RAM 才能正常執行吧。
版權許可
- 本作品 採用 知識共享 署名—相同方式共享 4.0 國際許可協議(CC BY-SA 4.0 International)許可,閣下可自由地共享(複製、發行) 和演繹(修改、轉換或二次創作) 這一作品,唯須遵守許可協議條款。

評論