如何在 Windows XP 和 Windows 2000 中使用 Pageheap.exe

文章翻譯 文章翻譯
文章編號: 286470 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

在此頁中

結論

本文將告訴您,如何在 Microsoft Windows XP 和 Microsoft Windows 2000 中使用「分頁堆積」工具 (Pageheap.exe)。

其他相關資訊

Pageheap.exe 會設定可用來協助尋找堆積相關損毀的分頁堆積旗標。它也可以協助偵測 Windows 2000 Professional Service Pack 2 (SP2) 和 Windows XP Professional 系統上執行程式中的遺漏問題。

Pageheap.exe 會在應用程式和系統之間,導入可驗證所有動態記憶體操作 (配置、釋放和其他堆積操作) 的軟體驗證層 (「分頁堆積」管理程式)。當「分頁堆積」管理程式啟用時,偵錯工具就會啟動要測試的應用程式。如果發生問題,它將造成偵錯工具中斷執行。

重要 Pageheap.exe 並不會在問題發生時指出錯誤為何,但是它會造成系統當機。它會從 Windows 2000 Professional SP2 和 Windows XP Professional,啟用已經存在於 Ntdll.dll 系統程式庫中的驗證層。Pageheap.exe 無法在舊版 Microsoft Windows 上運作。

如果偵錯工具沒有啟動要測試的應用程式,同時又遇到錯誤,這時它會造成系統當機,而不提供任何回應報告。

概念

應用程式開發的常見問題就是堆積損毀。通常,當應用程式配置指定大小的堆積記憶體區塊,接著又寫入超過所要求堆積區塊大小的記憶體位址時,就會發生這個問題。當應用程式寫入已釋放的記憶體區塊時,也會造成堆積損毀。

下面是瞭解 Pageheap.exe 相關命令和使用方式的兩項重要概念:
  • 在配置結束位址插入無法存取的分頁,或是在區塊釋放時檢查填充模式,便可找出堆積區塊中的損毀位置。
  • 已經啟用分頁堆積的處理程序,其所建立的每種堆積將具有兩種堆積類型 (完整分頁堆積和一般分頁堆積)。
    • 完整分頁堆積會在配置結束位址插入無法存取的分頁,顯示堆積區塊的損毀位置。這種方法的應用優點是會產生猝死 (Sudden-Death),也就是該處理程序會確實在錯誤發生位置存取違規 (AV)。這種作法可容易地找出錯誤。缺點則是每次配置時,至少都要用到一個分頁的認可記憶體。對於需要大量記憶體的處理程序而言,系統資源可能很快就會耗盡。
    • 一般分頁堆積可用在因記憶體限制而無法使用完整分頁堆積的情況。它會在堆積區塊釋放時檢查填充模式。這個方法的應用優點是,它可以大幅降低記憶體消耗量;缺點則是只能在區塊釋放時偵測到損毀。這種作法比較難找出錯誤。

Pageheap 工具的下載位置

如果要下載最新的偵錯工具套件,請按一下下列連結:
http://www.microsoft.com/taiwan/whdc/devtools/debugging/default.mspx


請選取最新版本的偵錯工具。當您在安裝這些工具時,請選取 [Custom] 安裝,並接著安裝到適當名稱的目錄中。例如,將工具安裝到 C:\Debug 或 C:\Debugtools。

選擇調查堆積區塊損毀的方法

大部分的堆積區塊損毀可由下列兩種方法其中之一找出:
  • 完整分頁堆積:在配置結束位址插入無法存取的分頁。
  • 一般分頁堆積:在區塊釋放時檢查填充模式。

完整分頁堆積

因為完整分頁堆積需要用到大量記憶體,所以這種方法應該從個別處理程序分別啟用,或是由大型處理程序透過限制參數來啟用。它不能從全系統層面啟用,因為這樣很難分析所需的分頁檔案大小。如果使用的分頁檔案與全系統的完整分頁堆積相對比例太小,就會導致系統無法開機。

完整分頁堆積的優點,就是它可使處理程序確實在錯誤發生位置存取違規 (AV),這樣可以容易地找出錯誤。為了找出錯誤,首先使用一般分頁堆積來判斷處理程序失敗的範圍,接著再從已限制類別配置 (也就是特定大小範圍或特定程式庫) 的個別大型處理程序使用完整分頁堆積。

一般分頁堆積

一般分頁堆積可用來測試大型處理程序,而不用像完整分頁堆積方法那樣大量耗用記憶體。但是,一般分頁堆積會延遲到區塊完成釋放才進行偵測,而這樣就會比較難偵測出錯誤。

一般而言,請使用一般分頁堆積來進行初始的大型處理程序測試。接著,如果偵測出問題,就要為這些處理程序中的已限制類別配置啟用完整分頁堆積。

所有處理程序都可以從全系統層面安全地啟用一般分頁堆積。這點在執行一般系統驗證的測試基準時非常有用,但是不適用於特定元件測試。單一處理程序也可以啟用一般分頁堆積。

使用 GFlags 配合全系統分頁堆積

GFlags 工具可以用來啟用全系統分頁堆積。為了使 GFlags 命令生效,您必須在發出命令之後重新啟動電腦。

如果要啟用全系統一般分頁堆積:
  1. 在命令列上輸入下列命令:gflags -r +hpa

  2. 重新啟動您的電腦。
如果要停用全系統一般分頁堆積:
  1. 在命令列上輸入下列命令:gflags -r -hpa

  2. 重新啟動您的電腦。
注意 啟用分頁堆積時,無法使用其他的 GFlags 設定。如果這時也有啟用與該堆積有關的其他設定,則在分頁堆積管理程式和這些「無害」堆積旗標之間的衝突,可能會產生分頁堆積錯誤。

使用 GFlags 配合單一處理程序分頁堆積

您可以啟用分頁堆積來監視一項特定的處理程序。如果要執行這項操作,請依照下列步驟執行:
  1. 在命令提示字元中,變更偵錯工具安裝的目錄。
  2. 在命令提示字元中輸入下列命令,然後按下 ENTER:
    Gflags.exe –p /enable lsass.exe
    注意 lsass.exe 代表您要使用 Pageheap 工具來監視的處理程序名稱。
  3. 當您不再需要進行分頁堆積監視時,請停用監視功能。如果要執行這項操作,請在命令提示字元中輸入下列命令,然後按下 ENTER:
    Gflags.exe -p /disable lsass.exe
    注意 lsass.exe 代表您要使用 Pageheap 工具來監視的處理程序名稱。
  4. 如果要列出目前已啟用 Pageheap 驗證的所有程式,請在命令提示字元中輸入下列命令,然後按下 ENTER
    Gflags.exe -p

未對齊的配置

Windows 堆積管理程式 (所有版本),永遠保證堆積配置的起始位址是 8 位元組對齊 (在 64 位元平台則是 16 位元組對齊)。分頁堆積管理程式也有相同的保證。但是,您絕對不可能讓配置結束位址剛好在分頁結束位址上。為了使 off-by-one-byte 錯誤觸發對無法存取的分頁進行讀取或寫入動作,並造成立即錯誤,必須取得確實的分頁結束位址配置。

如果使用者要求的區塊大小不是 8 位元組對齊,則分頁堆積便無法符合「起始位址是 8 位元組對齊」和「結束位址已對齊」兩個條件約束。解決方案就是符合第一個條件約束,使區塊的起始位址為 8 位元組對齊。接下來,在區塊結束位址和無法存取分頁的起始位址之間,使用小型填充模式。這個填充模式長度可為 0 位元組到 7 位元組的 32 位元結構。此填充模式將在釋放時檢查。

如果這些另外會在結束位址出現填充模式的配置需要立即偵測錯誤,請設定分頁堆積管理程式忽略 8 位元組對齊規則,並使用 /unaligned/full 參數,讓配置結束位址隨時對齊在分頁界線。如需詳細資訊,請參閱 /unaligned 參數。

注意:某些程式會假設為 8 位元組對齊,因此無法與 /unaligned 參數一起正確運作。Microsoft Internet Explorer 就是這類程式。

完整分頁堆積配置的未認可分頁

核心完整分頁堆積實作會為任何小於一個分頁的配置認可兩個分頁。其中一個分頁是用於使用者配置,另一個分頁則是成為緩衝區結束位址的無法存取分頁。

使用保留的虛擬空間區域 (而不要使用無法存取的認可分頁),便可偵測出緩衝區結束位址滿溢。當處理程序碰到該保留虛擬空間,就會發生存取違規例外狀況。這個方法最多可以降低 50% 的記憶體消耗量。如需詳細資訊,請參閱 /decommit 參數。

錯誤插入

您可以控制分頁堆積管理程式,刻意使某些配置失敗。這是不需實際用到所有系統資源,來模擬記憶體不足情況的好方法。

指定從 1 到 10,000 的數值,表示配置失敗的可能性。如果可能性是使用 10,000,則確保配置失敗的可能性是 100%。如果可能性是指定 2,000,就表示配置失敗的可能性大約是 20%。

這項分頁堆積管理程式會特別小心,避免在處理程序週期的前 5 秒鐘和 Windows NT 載入器程式碼路徑 (例如,LoadLibrary、FreeLibrary) 中發生錯誤插入。如果 5 秒鐘不足以讓處理程序完成啟動,則您可以在處理程序開頭指定較長的逾時時間。如需詳細資訊,請參閱 /fault 參數。

當您使用 /fault 參數,並在受測處理程序中找到錯誤,就會產生例外狀況。一般而言,例外狀況產生的原因是配置作業傳回 NULL,而應用程式又接著嘗試存取該配置記憶體。但是因為配置已經失敗,所以無法存取該記憶體,進而導致存取違規發生。

產生例外狀況的另一個原因是因為應用程式嘗試處理配置失敗,但未釋放部分資源。這樣將出現記憶體遺漏,而且更難進行偵錯。

為了協助診斷這些失敗情形,此分頁堆積管理程式會保留從錯誤插入開始之後的堆疊追蹤記錄。使用下列偵錯工具命令,便可顯示這些追蹤:

!heap -p -f [NUMBER-OF-TRACES]

根據預設,展開部分只會顯示最後四次的追蹤。

在應用程式啟動時自動連接偵錯工具

某些應用程式很難透過命令提示字元啟動,或者要從其他處理程序進行啟動。對於這類應用程式,您就要指定在它們啟動時自動連接偵錯工具。在處理程序已啟用分頁堆積,而且發生堆積失敗的情況下,這是非常好用的設定。如需詳細資訊,請參閱 /debug 參數。

只要自訂配置/釋放函式最後會呼叫 NT 堆積管理介面 (也就是 RtlAllocateHeap、RtlFreeHeap),Pageheap.exe 就可有效地用來驗證任何記憶體配置處理程序,包括 C++ 樣式配置的新增和刪除。下列函式可以執行這項功能:
  • HeapAllocHeapFreeHeapReAlloc 函式:這些函式是由 kernel32.dll 匯出,而且會直接呼叫 NT 堆積介面。如 GlobalAllocGlobalFreeGlobalReAlloc 函式:這些函式是由 kernel32.dll 匯出,而且會直接或間接呼叫 NT 堆積介面。
  • LocalAllocLocalFreeLocalReAlloc 函式:這些函式是由 kernel32.dll 匯出,而且會直接或間接呼叫 NT 堆積介面。
  • mallocfreereallocmsizeexpand 函式:這些函式是由 msvcrt.dll 匯出,而且會直接或間接呼叫 NT 堆積。但情況並非總是如此。過去 C Run-Time 會產生不同的堆積實作,但是現在的 C Run-Time 會直接呼叫 NT 堆積。
  • newdeletenew[ ]delete[ ] 運算子:這些函式是由 msvcrt.dll 匯出,而且會直接或間接呼叫 NT 堆積。
任何其他配置/函式的釋放組合可能是自訂配置,而且不保證會直接或間接呼叫 NT 堆積。這時只能透過原始程式碼檢查或從偵錯工具執行,才可以顯示實際的實作情形。

避免使用靜態連結。某些應用程式已經靜態連結到舊版的 C Runtime。這類舊版本不會呼叫 Windows NT 堆積 API,因此無法使用 Pageheap.exe 來驗證這些配置。動態連結可確保您取得最新版本的 C Runtime 程式庫 (msvcrt.dll)。

Pageheap.exe 可找出的錯誤類別

Pageheap.exe 可偵測出大多數的堆積相關錯誤;但是它著重於堆積損毀問題,而不是遺漏問題。Pageheap.exe 雖然有偵測堆積遺漏的能力,但是效果有限。

Pageheap.exe 的其中一項優點,就是許多錯誤可在發生時立即受到偵測。例如,在動態配置緩衝區結束位址的 off-by-one-byte 錯誤,可能會導致即時存取違規。少數種類的錯誤無法在發生時立即受到偵測。在這種情況下,錯誤報告會延遲到區塊釋放之後才產生。
  • 無效的堆積指標:所有 Win32 和 Windows NT 層級的堆積介面,其中的第一個參數為指標,能指示堆積從何處開始進行作業。此分頁堆積管理程式在呼叫完成時,偵測出無效的堆積指標。
  • 無效的堆積區塊指標:區塊在完成配置之後,便可作為多種堆積介面的參數,特別是 free() 類別介面。分頁堆積管理程式可以立即偵測出無效的堆積區塊指標。請參閱「偵錯分頁堆積失敗」,了解如何判斷無效位址是偏差幾個位元組或是完全不正確。
  • 多執行緒非同步的堆積存取:某些應用程式會透過多執行緒呼叫堆積。進行這種呼叫情形時,(使用者) 必須設定可觸發取得堆積區塊的旗標。分頁堆積管理程式會在兩個執行緒同時嘗試呼叫特定堆積時,偵測出這類型的違規。
  • 假設區塊重新配置到相同位址:重新配置作業不一定會傳回相同位址。特別是在重新配置減少區塊大小時,更不一定會傳回相同位址。某些應用程式會假設重新配置將傳回相同位址。分頁堆積管理程式會一直在重新配置時配置新區塊,並釋放舊區塊。此釋放區塊的讀取/寫入存取會受到保護;因此,如果對其進行任何存取,將引發存取違規。
  • 重複釋放:這種釋放好幾次相同堆積區塊的情形,是某些應用程式中的常見錯誤。這種錯誤會立即被分頁堆積管理程式偵測出,因為區塊在第二次釋放時,將沒有正確的首碼標頭,因此在已配置區塊中無法找到此區塊。請參閱「偵錯分頁堆積失敗」,了解如何分析第一次釋放作業的堆疊追蹤。這項錯誤是重新配置問題的變化,因為當應用程式釋放其所認為區塊位址的區塊時,該區塊早已透過重新配置完成釋放。
  • 存取釋放後區塊:分頁堆積管理程式會在受保護的記憶體集區中,短期保存已釋放的記憶體區塊。只要這些區塊一遭到存取,就會引發存取違規。根據「位置」原則,如果該釋放的保護集區夠大,便應該可以找出大多數的問題。如果該釋放區塊仍在保護集區中,就可以立刻發現該錯誤。但是,如果此時該記憶體重新使用,找出錯誤或是辨識造成錯誤之程式碼的機會就會降低。
  • 存取已配置區塊結束位址後之區塊:分頁堆積管理程式會在配置區塊之後,緊接著插入無法存取的分頁。只要區塊結束位址後面的區塊一遭到存取,就會引發存取違規。某些應用程式預期配置是 8 位元組對齊。這項功能已自 Windows NT 3.5 堆積管理程式起受到支援。要求大小如果不是 8 位元組對齊,還是可以取得 8 位元組對齊位址,但是這樣會導致區塊結束位址後面出現少數可存取的位元組。如果應用程式僅損毀這些少數位元組,則只有當區塊釋放後檢查區塊尾碼模式時,才會找到這項錯誤。
  • 存取已配置區塊起始位址之前區塊:您可以透過可設定旗標指示此分頁堆積管理程式,在區塊開頭位置插入無法存取的分頁,而不是插入到結束位址。只要區塊起始位址之前的區塊一遭到存取,就會引發存取違規。
摺疊此表格展開此表格
失敗一般分頁堆積完整分頁堆積
無效的堆積指標立刻發現立刻發現
無效的堆積區塊指標立刻發現立刻發現
非同步的存取立刻發現立刻發現
假設重新配置位址直到確實釋放發現率 90%立刻發現率 90%
重複釋放立刻發現率 90%立刻發現率 90%
重新使用釋放後區塊直到確實釋放發現率 90%立刻發現率 90%
存取區塊結束位址後區塊釋放時發現立刻發現
存取區塊起始位址後區塊釋放時發現立刻發現 (特殊旗標)

偵錯分頁堆積失敗

如需有關「偵錯分頁堆積失敗」的詳細資訊,請參閱 Application Compatibility Toolkit 所提供的 Application Compatibility Tookit Reference

如果要取得 Pageheap.exe 的語法說明及其使用範例,請參閱 Application Compatibility Toolkit 所提供的 Application Compatibility Tookit Reference

如需詳細資訊,請參閱「Microsoft 知識庫」中的下列文件:
294895 如何取得 Windows Application Compatibility Toolkit

屬性

文章編號: 286470 - 上次校閱: 2006年4月20日 - 版次: 4.1
這篇文章中的資訊適用於:
  • Microsoft Windows Server 2003, Standard Edition (32-bit x86)
  • Microsoft Windows Server 2003, Enterprise Edition (32-bit x86)
  • Microsoft Windows Server 2003, Datacenter Edition (32-bit x86)
  • Microsoft Windows XP Professional
  • Microsoft Windows XP Home Edition (家用版)
  • Microsoft Windows 2000 Professional Edition
  • Microsoft Windows 2000 Server
  • Microsoft Windows 2000 Advanced Server
  • Microsoft Windows 2000 Datacenter Server
關鍵字:?
kbinfo kbenv KB286470
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。

提供意見

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com