以文本方式查看主題 - 昂捷論壇 (http://www.26035.net/bbs/index.asp) -- □-技術(shù)研討會 (http://www.26035.net/bbs/list.asp?boardid=36) ---- 對于堆內(nèi)存分配的專業(yè)說明(摘自MSDN) (http://www.26035.net/bbs/dispbbs.asp?boardid=36&id=6621) |
-- 作者:飛絮 -- 發(fā)布時間:2009/11/24 17:29:10 -- 對于堆內(nèi)存分配的專業(yè)說明(摘自MSDN)
Murali R. Krishnan 1999 年 2 月 摘要:討論常見的堆性能問題以及如何避免這些問題。(共 9 頁打印頁) 介紹您是在無憂無慮地使用動態(tài)分配的 C/C++ 對象嗎?您廣泛地使用自動化在模塊之間相互通訊嗎?您的程序可能因為堆分配而變慢嗎?以上這些情況不只是您一個人遇到的。幾乎所有的項目遲早都會遇到堆問題。一般的傾向是說:"是堆慢,而我的代碼確實是好代碼。"這不完全正確。本文幫助您更多地了解堆、堆的用法以及可能產(chǎn)生的問題。 什么是堆?(如果您已經(jīng)知道什么是堆,則可以向前跳轉(zhuǎn)到一節(jié)) 堆用于動態(tài)分配和釋放程序所使用的對象。在以下情況中調(diào)用堆操作:
堆使用運行期間分配給代碼和堆棧以外的部分內(nèi)存。下圖顯示堆分配器的不同層。 GlobalAlloc/GlobalFree:直接與每個進程的默認(rèn)堆通訊的 Microsoft Win32 堆調(diào)用。 LocalAlloc/LocalFree:直接與每個進程的默認(rèn)堆通訊的 Win32 堆調(diào)用(用于與 Microsoft Windows NT 的兼容性)。 COM 的 IMalloc 分配器(或 CoTaskMemAlloc / CoTaskMemFree):函數(shù)使用默認(rèn)的每個進程堆。自動化使用組件對象模型 (COM) 的分配器,而請求使用每進程堆。 C/C++ 運行時 (CRT) 分配器:提供 malloc() 和 free() 以及 new 和 delete 運算符。編程語言如 Microsoft Visual Basic 和 Java 還提供新運算符,它們使用的是垃圾回收而不是堆。CRT 創(chuàng)建自己的駐留在 Win32 堆之上的專用堆。 在 Windows NT 中,Win32 堆是圍繞 Windows NT 運行時分配器的一個薄層。所有的 API 都將它們的請求轉(zhuǎn)發(fā)到 NTDLL。 在 Windows NT 中,Windows NT 運行時分配器提供了該核心堆分配器。它包含一個前端分配器,該分配器具有 128 個大小從 8 到 1,024 字節(jié)不等的自由列表。后端分配器使用虛擬內(nèi)存保留和提交頁面。 圖表的底部是虛擬內(nèi)存分配器,它保留和提交操作系統(tǒng)使用的頁面。所有的分配器都使用虛擬內(nèi)存設(shè)備訪問數(shù)據(jù)。 分配和釋放塊不是很簡單嗎?為什么這要花費很長的時間? 有關(guān)堆實現(xiàn)的說明傳統(tǒng)上,操作系統(tǒng)和運行時庫隨附了堆實現(xiàn)。當(dāng)進程開始時,操作系統(tǒng)創(chuàng)建稱為進程堆的默認(rèn)堆。如果沒有使用其他堆,則使用進程堆分配塊。語言運行時庫也可在一個進程內(nèi)創(chuàng)建單獨的堆。(例如,C 運行時庫創(chuàng)建自己的堆。)除這些專用堆外,應(yīng)用程序或許多加載的動態(tài)鏈接庫 (DLL) 之一也可以創(chuàng)建并使用單獨的堆。Win32 提供了一組豐富的 API 用于創(chuàng)建和使用專用堆。有關(guān)堆函數(shù)的優(yōu)秀教程,請參閱 MSDN 平臺 SDK 節(jié)點。 當(dāng)應(yīng)用程序或 DLL 創(chuàng)建專用堆時,這些堆駐留于進程空間中并且在進程范圍內(nèi)是可訪問的。某一給定堆分配的任何數(shù)據(jù)應(yīng)為同一堆所釋放。(從一個堆分配并釋放給另一個堆沒有意義。) 在所有虛擬內(nèi)存系統(tǒng)中,堆位于操作系統(tǒng)的虛擬內(nèi)存管理器之上。語言運行時堆也駐留在虛擬內(nèi)存之上。某些情況下,這些堆在操作系統(tǒng)堆的上層,但語言運行時堆通過分配大的塊來執(zhí)行自己的內(nèi)存管理。繞開操作系統(tǒng)堆來使用虛擬內(nèi)存函數(shù)可使堆更好地分配和使用塊。 典型的堆實現(xiàn)由前端分配器和后端分配器組成。前端分配器維護固定大小塊的自由列表。當(dāng)堆收到分配調(diào)用后,它嘗試從前端列表中查找自由塊。如果此操作失敗,則堆將被迫從后端(保留和提交虛擬內(nèi)存)分配一個大塊來滿足請求。通常的實現(xiàn)具有每個塊分配的開銷,這花費了執(zhí)行周期,也減少了可用存儲區(qū)。 知識庫文章 Q10758"Managing Memory with calloc() and malloc()"(按文章 ID 號搜索)包含有關(guān)這些主題的更多背景知識。另外,有關(guān)堆實現(xiàn)和設(shè)計的詳細(xì)討論,請參閱 Paul R. Wilson、Mark S. Johnstone、Michael Neely 和 David Boles 所著的"Dynamic Storage Allocation: A Survey and Critical Review"。"International Workshop on Memory Management",Kinross,Scotland,UK,1995 年 9 月 (http://www.cs.utexas.edu/users/oops/papers.html)。 Windows NT 的實現(xiàn)(Windows NT 4.0 版及更高版本)使用 127 個從 8 到 1,024 字節(jié)不等的 8 字節(jié)對齊塊的自由列表和 1 個混合列表;旌狭斜恚ㄗ杂闪斜韀0])包含大小超過 1,024 字節(jié)的塊。自由列表包含在雙向鏈接表中鏈接在一起的對象。默認(rèn)情況下,進程堆執(zhí)行合并操作。(合并操作是組合相鄰的自由塊以生成更大的塊的操作。)合并操作花費了額外的周期,但減少了堆塊的內(nèi)部碎片。 單個全局鎖可防止多線程同時使用堆。(請參閱 George Reilly 寫的服務(wù)器性能和可伸縮性殺手锏的第一條戒律。)此鎖主要用于保護堆數(shù)據(jù)結(jié)構(gòu)不受多線程的任意訪問。當(dāng)堆操作過于頻繁時,此鎖會對性能造成負(fù)面影響。 常見的堆性能問題有哪些?以下是在使用堆時會遇到的最常見問題:
在分配及釋放操作中,爭用是使速度降低的原因。理想情況下,我們希望有一個沒有爭用且快速分配/釋放的堆。哎,這樣的通用用途堆尚不存在,盡管在將來某個時候也許會出現(xiàn)。 在所有的服務(wù)器系統(tǒng)(如 IIS、MSProxy、DatabaseStacks、網(wǎng)絡(luò)服務(wù)器、Exchange 等等)中,堆鎖都是一個"大"瓶頸。處理器的數(shù)目越多,爭用越厲害。 保護自己不受堆的影響既然您知道了關(guān)于堆的一些問題,難道不想要一根解決這些問題的魔棒嗎?我希望有一根魔棒。但是沒有魔法使堆運行得更快,因此不要期望在發(fā)行產(chǎn)品的前一個星期內(nèi)使速度加快。請盡早計劃您的堆策略,這樣會好得多。改變使用堆的方式并減少堆操作數(shù)是提高性能的可靠策略。 如何減少堆操作的使用呢?可以通過在數(shù)據(jù)結(jié)構(gòu)內(nèi)使用位置來減少堆操作數(shù)?紤]下面的示例: struct ObjectA {
通過使用上述技巧獲得的節(jié)省因?qū)ο箢愋、大小和工作?fù)荷而異。但總是能獲得性能和可縮放性方面的好處。退一步說,代碼會有點專用,但是如果認(rèn)真思考,代碼還是可以易于管理的。 更多性能提升以下是一些提升速度的更多技巧:
摘要堆實現(xiàn)趨于對所有平臺保持通用,因此具有巨大的系統(tǒng)開銷。每個人的代碼都有特定的要求,但是設(shè)計可以適應(yīng)本文所討論的原則以減少堆交互。
Murali Krishnan 是 Internet Information Server (IIS) 團隊的首席軟件設(shè)計工程師。他從 1.0 版就開始研究 IIS,并成功地將 IIS 從 1.0 版一直升級到 4.0。Murali 組織和領(lǐng)導(dǎo)了 IIS 性能小組三年 (1995-1998),并從第一天起就開始改變 IIS 的性能。他在印第安納州的 Anna 大學(xué)獲得計算機科學(xué)學(xué)士學(xué)位,并在 Wisconsin-Madison 大學(xué)獲得計算機科學(xué)碩士學(xué)位。工作之余,他喜歡讀書、打排球和在家烹飪。 <!--Footer Start--> |
-- 作者:ccav123 -- 發(fā)布時間:2012/1/5 12:26:43 -- win2k對堆的管理基本上已經(jīng)公開了,雖然是未文檔化的。 基本上現(xiàn)在已經(jīng)對以前的堆管理做了很大的優(yōu)化,尤其是關(guān)于堆的安全方面。 對堆的使用在任何程序里是必須的,堆的申請和釋放必須由程序員來維護。 |