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