首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

MFC 屏幕抓圖傳輸「內存不足」排查指南

     編輯:程式設計綜合問答

現象

客戶端點擊「獲取屏幕」即彈出 Out of Memory,且無法定位具體代碼行。

核心排查思路

  1. 圖像尺寸過大:4K 屏 3840×2160×32bit ≈ 32 MB/幀,若未壓縮直接在內存拼裝多幀,極易耗盡 32 位進程 2 GB 虛擬地址空間。
  2. GDI 對象泄漏:CreateCompatibleBitmap/CreateCompatibleDC 後未 DeleteObject/DeleteDC,導致 GDI 對象計數飆升(上限 10k/進程),觸發分配失敗並誤報「內存不足」。
  3. 發送緩衝區堆積:發送端產生速度 > 網絡發送速度,send 非阻塞模式下數據在應用層隊列無限增長。

定位代碼的「插桩法」

// 在可疑函數入口/出口插入
TRACE(_T(">>> Enter CaptureScreen, GDI Count=%d\n"), GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS));
try {
    // 原邏輯
} catch (CMemoryException* e) {
    AfxMessageBox(_T("CMemoryException caught!"));
    e->Delete();
}
TRACE(_T("<<< Leave CaptureScreen, GDI Count=%d\n"), GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS));

觀察輸出窗口 GDI 計數變化,鎖定泄漏函數。

修復清單

問題修復
位圖過大抓取前按比例縮放(如 50%),或直接用 StretchBlt 繪制到較小 DC;採用 JPEG/PNG 壓縮(GDI+ / libjpeg-turbo)再發送。
GDI 泄漏嚴格遵循 誰創建誰釋放,用 CBitmap/CDC 等 MFC 封裝類利用 RAII 自動釋放。
發送堆積發送端引入背壓機制:發送隊列達高水位暫停抓屏;或改用 UDP + FEC 容忍丟包。
32位地址空間耗盡編譯為 x64 Release,虛擬地址空間 128 TB,徹底解決大內存分配失敗。

調試技巧

  • 用 Visual Studio 診斷工具(Alt+F2)監控堆/托管堆/非托管堆走勢。
  • !address -summary (WinDbg) 查看堆碎片。
  • 最小復現:註釋網絡發送,僅循環抓屏 100 次觀察內存/ GDI 是否增長。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved