防止 Windows 應用程式中的記憶體流失
受影響的平臺
用戶端 - Windows 7
伺服器 - Windows Server 2008 R2
描述
記憶體洩漏是一種 Bug 類別,指當不再需要時,應用程式無法釋放記憶體。 經過一段時間,記憶體流失會影響特定應用程式與作系統的效能。 由於分頁過多,大規模洩漏可能會導致無法容忍的反應時間。 最終,應用程式以及作系統的其他部分將經歷失敗。
Windows 會在進程終止時釋放應用程式配置的所有記憶體,因此短期執行的應用程式不會影響整體系統效能。 不過,長時間執行的進程,例如服務或甚至是 Explorer 的外掛程式,可能會嚴重影響系統的可靠性,甚至可能強迫使用者重新啟動 Windows,使系統能再次使用。
應用程式可以透過多個方式代表其配置記憶體。 如果使用後未釋放,則每種分配類型都可能會導致洩漏。 以下是常見配置模式的一些範例:
- 透過 HeapAlloc 函式或其 C/C++ 執行時間對等專案 malloc 或 新的 堆積記憶體
- 透過作業系統的 VirtualAlloc 函式直接配置。
- 透過 Kernel32 API 建立的核心句柄,例如 CreateFile、CreateEvent或 CreateThread,代表應用程式保留核心記憶體
- 透過 User32 和 Gdi32 API 建立的 GDI 和 USER 句柄(根據預設,每個進程都有 10,000 個句柄的配額)
最佳做法
監視應用程式一段時間的資源耗用量,是偵測和診斷記憶體流失的第一個步驟。 使用 Windows 任務管理員並新增下列數據行:「認可大小」、「句柄」、「用戶物件」和「GDI 物件」。 這可讓您建立應用程式的基準,並監視一段時間的資源使用量。
下列Microsoft工具提供更詳細的資訊,並有助於偵測和診斷應用程式中各種配置類型的洩漏:
- 性能監視器和資源監視器是 Windows 7 的一部分,可監視和圖表一段時間的資源使用
- 最新版本的 Application Verifier 可以診斷 Windows 7 上的記憶體堆積洩漏問題。
- UMDH 是 Windows 偵錯工具的一部分,會分析指定進程的堆積記憶體配置,並有助於尋找流失和其他不尋常的使用模式
- Xperf 是一種複雜的效能分析工具,可支援堆積配置追蹤
- CRT 偵錯堆積會追蹤堆積配置,並可協助建置您自己的堆積偵錯功能
某些程式代碼撰寫和設計做法可以限制程式代碼中的流失次數。
- 在C++程式碼中,使用智慧指標來管理堆記憶體分配以及 Win32 資源,如內核 HANDLE等。 C++ 標準函式庫提供用於堆記憶體配置的 auto_ptr 類別。 針對其他分配類型,您必須編寫自己的類別。 ATL 程式庫提供一組豐富的類別,可用於堆區物件和核心控制代碼的自動資源管理。
- 使用編譯程式內建功能,例如 _com_ptr_t 將 COM 介面指標封裝成「智慧型指標」,並協助進行參考計數。 其他 COM 數據類型也有類似的類別:_bstr_t 和 _variant_t
- 監視 .NET 程式代碼不尋常的記憶體使用量。 受控代碼不免於記憶體洩漏。 要了解如何查找 GC 洩漏,請參閱 「查找受控記憶體洩漏」。
- 請注意 Web 用戶端程式代碼中的外洩模式。 COM 物件與腳本引擎(例如 JScript)之間的循環參考可能會導致網頁應用程式中發生大量記憶體洩漏。 「瞭解和解決 Internet Explorer 洩漏模式」 有這類洩漏的詳細資訊。 您可以使用 JavaScript 記憶體流失偵測器來偵錯程式代碼中的記憶體流失。 雖然隨附於 Windows 7 的 Windows Internet Explorer 8 可減輕這些問題的大部分問題,但較舊的瀏覽器仍然容易受到這些 Bug 的影響
- 避免使用函式中的多個結束路徑。 指派給函式範圍變數的配置應該在函式結尾的一個特定區塊中釋放
- 請勿在程序代碼中使用例外狀況,而不釋放函式中的所有局部變數。 如果您使用原生例外狀況,請在 __finally 區塊內釋放所有配置。 如果您使用 C++ 異常,所有的堆積和處理配置都必須包裝在智慧指標中。
- 請勿捨棄或重新初始化 PROPVARIANT 物件,而不呼叫 PropVariantClear 函式
資源的連結
常見的配置模式:
Microsoft 工具:
- 應用程式驗證程式
- 適用於 Windows 的 偵錯工具
- User-Mode 傾印堆積
- 追蹤擷取、處理和分析工具
- CRT 偵錯堆
其他連結:
- auto_ptr 類別
- Active Template Library (ATL) 記憶體類別
- _com_ptr_t 物件
- _bstr_t 類別
- _variant_yt 類別
- 「追蹤受控記憶體流失」
- 「瞭解及解決 Internet Explorer 洩漏模式」
- “JavaScript 記憶體流失偵測器”
- 迴圈記憶體流失風險降低功能(在瀏覽器中):
- try-finally 敘述
- PROPVARIANT 結構
- PropVariantClear 函式