• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎(chǔ)} {C++ 高級} {C#界面,C++核心算法} {設(shè)計(jì)模式} {C#基礎(chǔ)}

            windows核心編程--內(nèi)存堆棧

            對內(nèi)存進(jìn)行操作的第三個機(jī)制是使用堆棧。堆棧可以用來分配許多較小的數(shù)據(jù)塊。例如,若要對鏈接表和鏈接樹進(jìn)行管理,最好的方法是使用堆棧,堆棧的優(yōu)點(diǎn)是,可以不考慮分配粒度和頁面邊界之類的問題,集中精力處理手頭的任務(wù)。堆棧的缺點(diǎn)是,分配和釋放內(nèi)存塊的速度比其他機(jī)制要慢,并且無法直接控制物理存儲器的提交和回收。
            從內(nèi)部來講,堆棧是保留的地址空間的一個區(qū)域。開始時(shí),保留區(qū)域中的大多數(shù)頁面沒有被提交物理存儲器。當(dāng)從堆棧中進(jìn)行越來越多的內(nèi)存分配時(shí),堆棧管理器將把更多的物理存儲器提交給堆棧。物理存儲器總是從系統(tǒng)的頁文件中分配的,當(dāng)釋放堆棧中的內(nèi)存塊時(shí),堆棧管理器將收回這些物理存儲器。

            線程的堆棧:

            每當(dāng)創(chuàng)建一個線程時(shí),系統(tǒng)就會為線程的堆棧(每個線程有它自己的堆棧)保留一個堆棧空間區(qū)域,并將一些物理存儲器提交給這個已保留的區(qū)域。按照默認(rèn)設(shè)置,系統(tǒng)保留1 MB的地址空間并提交兩個頁面的內(nèi)存。但是,這些默認(rèn)值是可以修改的,方法是在你鏈接應(yīng)用程序時(shí)設(shè)定M i c r o s o f t的鏈接程序的/ S TA C K選項(xiàng):

            /STACK:reserve[,commit]

            當(dāng)創(chuàng)建一個線程的堆棧時(shí),系統(tǒng)將會保留一個鏈接程序的/ S TA C K開關(guān)指明的地址空間區(qū)域。
            進(jìn)程的默認(rèn)堆棧

            當(dāng)進(jìn)程初始化時(shí),系統(tǒng)在進(jìn)程的地址空間中創(chuàng)建一個堆棧。該堆棧稱為進(jìn)程的默認(rèn)堆棧。按照默認(rèn)設(shè)置,該堆棧的地址空間區(qū)域的大小是1 MB。但是,系統(tǒng)可以擴(kuò)大進(jìn)程的默認(rèn)堆棧,使它大于其默認(rèn)值。當(dāng)創(chuàng)建應(yīng)用程序時(shí),可以使用/ H E A P鏈接開關(guān),改變堆棧的1 M B默認(rèn)區(qū)域大小。由于D L L沒有與其相關(guān)的堆棧,所以當(dāng)鏈接D L L時(shí),不應(yīng)該使用/ H E A P鏈接開關(guān)。/ H E A P鏈接開關(guān)的句法如下:

            /HEAP:reserve[,commit]

            許多Wi n d o w s函數(shù)要求進(jìn)程使用其默認(rèn)堆棧。特別是widows提供的API。對默認(rèn)堆棧的訪問是順序進(jìn)行的。換句話說,系統(tǒng)必須保證在規(guī)定的時(shí)間內(nèi),每次只有一個線程能夠分配和釋放默認(rèn)堆棧中的內(nèi)存塊。如果兩個線程試圖同時(shí)分配默認(rèn)堆棧中的內(nèi)存塊,那么只有一個線程能夠分配內(nèi)存塊,另一個線程必須等待第一個線程的內(nèi)存塊分配之后,才能分配它的內(nèi)存塊。一旦第一個線程的內(nèi)存塊分配完,堆棧函數(shù)將允許第二個線程分配內(nèi)存塊。這種順序訪問方法對速度有一定的影響。如果你的應(yīng)用程序只有一個線程,并且你想要以最快的速度訪問堆棧,那么應(yīng)該創(chuàng)建你自己的獨(dú)立的堆棧,不要使用進(jìn)程的默認(rèn)堆棧。

            單個進(jìn)程可以同時(shí)擁有若干個堆棧。這些堆棧可以在進(jìn)程的壽命期中創(chuàng)建和撤消。但是,默認(rèn)堆棧是在進(jìn)程開始執(zhí)行之前創(chuàng)建的,并且在進(jìn)程終止運(yùn)行時(shí)自動被撤消。不能撤消進(jìn)程的默認(rèn)堆棧。每個堆棧均用它自己的堆棧句柄來標(biāo)識,用于分配和釋放堆棧中的內(nèi)存塊的所有堆棧函數(shù)都需要這個堆棧句柄作為其參數(shù)。

            可以通過調(diào)用G e t P r o c e s s H e a p函數(shù)獲取你的進(jìn)程默認(rèn)堆棧的句柄:

            HANDLE GetProcessHeap();

            為什么要創(chuàng)建輔助堆棧

            除了進(jìn)程的默認(rèn)堆棧外,可以在進(jìn)程的地址空間中創(chuàng)建一些輔助堆棧。由于下列原因,你可能想要在自己的應(yīng)用程序中創(chuàng)建一些輔助堆棧:

            ? 保護(hù)組件。

            ? 更加有效地進(jìn)行內(nèi)存管理。

            ? 進(jìn)行本地訪問。

            ? 減少線程同步的開銷。

            ? 迅速釋放。

            保護(hù)組件
            通過創(chuàng)建多個獨(dú)立的堆棧,是數(shù)據(jù)隔離,且相互獨(dú)立的操作。
            更有效的內(nèi)存管理

            通過在堆棧中分配同樣大小的對象,就可以更加有效地管理堆棧。就是把大小相同的對象放在一個堆棧中進(jìn)行分配。
            進(jìn)行本地訪問

            每當(dāng)系統(tǒng)必須在R A M與系統(tǒng)的頁文件之間進(jìn)行R A M頁面的交換時(shí),系統(tǒng)的運(yùn)行性能就會受到很大的影響。如果經(jīng)常訪問局限于一個小范圍地址的內(nèi)存,那么系統(tǒng)就不太可能需要在R A M與磁盤之間進(jìn)行頁面的交換。

            所以,在設(shè)計(jì)應(yīng)用程序的時(shí)候,如果有些數(shù)據(jù)將被同時(shí)訪問,那么最好把它們分配在互相靠近的位置上。
            減少線程同步的開銷

            正如下面就要介紹的那樣,按照默認(rèn)設(shè)置,堆棧是順序運(yùn)行的,這樣,如果多個線程試圖同時(shí)訪問堆棧,就不會使數(shù)據(jù)受到破壞。但是,堆棧函數(shù)必須執(zhí)行額外的代碼,以保證堆棧對線程的安全性。如果要進(jìn)行大量的堆棧分配操作,那么執(zhí)行這些額外的代碼會增加很大的負(fù)擔(dān),從而降低你的應(yīng)用程序的運(yùn)行性能。當(dāng)你創(chuàng)建一個新堆棧時(shí),可以告訴系統(tǒng),只有一個線程將訪問該堆棧,因此額外的代碼將不執(zhí)行。(就是用多個堆棧來減少同步的性能消耗)
            迅速釋放堆棧

            最后要說明的是,將專用堆棧用于某些數(shù)據(jù)結(jié)構(gòu)后,就可以釋放整個堆棧,而不必顯式釋放堆棧中的每個內(nèi)存塊。例如,當(dāng)Windows Explorer遍歷硬盤驅(qū)動器的目錄層次結(jié)構(gòu)時(shí),它必須在內(nèi)存中建立一個樹狀結(jié)構(gòu)。如果你告訴Windows Explorer刷新它的顯示器,它只需要撤消包含這個樹狀結(jié)構(gòu)的堆棧并且重新運(yùn)行即可(當(dāng)然,假定它將專用堆棧用于存放目錄樹信息)。對于許多應(yīng)用程序來說,這是非常方便的,并且它們也能更快地運(yùn)行。

            如何創(chuàng)建輔助堆棧

            你可以在進(jìn)程中創(chuàng)建輔助堆棧,方法是讓線程調(diào)用H e a p C r e a t e函數(shù):

            HANDLE HeapCreate(
               DWORD fdwOptions,
               SIZE_T dwInitialSize,
               SIZE_T dwMaximumSize);

            當(dāng)試圖從堆棧分配一個內(nèi)存塊時(shí), H e a p A l l o c函數(shù)(下面將要介紹)必須執(zhí)行下列操作:

            1) 遍歷分配的和釋放的內(nèi)存塊的鏈接表。

            2) 尋找一個空閑內(nèi)存塊的地址。

            3) 通過將空閑內(nèi)存塊標(biāo)記為“已分配”分配新內(nèi)存塊。

            4) 將新內(nèi)存塊添加給內(nèi)存塊鏈接表。

            從堆棧中分配內(nèi)存塊

            若要從堆棧中分配內(nèi)存塊,只需要調(diào)用H e a p A l l o c函數(shù):

            PVOID HeapAlloc(
               HANDLE hHeap,
               DWORD fdwFlags,
               SIZE_T dwBytes);

            改變內(nèi)存塊的大小

            常常需要改變內(nèi)存塊的大小。有些應(yīng)用程序開始時(shí)分配的內(nèi)存塊比較大,然后,當(dāng)所有數(shù)據(jù)放入內(nèi)存塊后,再縮小內(nèi)存塊的大小。有些應(yīng)用程序開始時(shí)分配的內(nèi)存塊比較小,后來需要將更多的數(shù)據(jù)拷貝到內(nèi)存塊中去時(shí),再設(shè)法擴(kuò)大它的大小。如果要改變內(nèi)存塊的大小,可以調(diào)用H e a p R e A l l o c函數(shù):

            PVOID HeapReAlloc(
               HANDLE hHeap,
               DWORD fdwFlags,
               PVOID pvMem,
               SIZE_T dwBytes);

            了解內(nèi)存塊的大小

            當(dāng)內(nèi)存塊分配后,可以調(diào)用H e a p S i z e函數(shù)來檢索內(nèi)存塊的實(shí)際大小:

            SIZE_T HeapSize(
               HANDLE hHeap,
               DWORD fdwFlags,
               LPCVOID pvMem);

            釋放內(nèi)存塊

            當(dāng)不再需要內(nèi)存塊時(shí),可以調(diào)用H e a p F r e e函數(shù)將它釋放:

            BOOL HeapFree(
               HANDLE hHeap,
               DWORD fdwFlags,
               PVOID pvMem);

            撤消堆棧

            如果應(yīng)用程序不再需要它創(chuàng)建的堆棧,可以通過調(diào)用H e a p D e s t r o y函數(shù)將它撤消:

            BOOL HeapDestroy(HANDLE hHeap);

            調(diào)用H e a p D e s t r o y函數(shù)可以釋放堆棧中包含的所有內(nèi)存塊,也可以將堆棧占用的物理存儲器和保留的地址空間區(qū)域重新返回給系統(tǒng)。如果該函數(shù)運(yùn)行成功, H e a p D e s t r o y返回T R U E。如果在進(jìn)程終止運(yùn)行之前沒有顯式撤消堆棧,那么系統(tǒng)將為你將它撤消。但是,只有當(dāng)進(jìn)程終止運(yùn)行時(shí),堆棧才能被撤消。如果線程創(chuàng)建了一個堆棧,當(dāng)線程終止運(yùn)行時(shí),該堆棧將不會被撤消。

            在進(jìn)程完全終止運(yùn)行之前,系統(tǒng)不允許進(jìn)程的默認(rèn)堆棧被撤消。如果將進(jìn)程的默認(rèn)堆棧的句柄傳遞給H e a p D e s t r o y函數(shù),系統(tǒng)將忽略對該函數(shù)的調(diào)用。

            由于進(jìn)程的地址空間中可以存在多個堆棧,因此可以使用G e t P r o c e s s H e a p s函數(shù)來獲取現(xiàn)有堆棧的句柄:

            DWORD GetProcessHeaps(
               DWORD dwNumHeaps,
               PHANDLE pHeaps);

            若要調(diào)用G e t P r o c e s s H e a p s函數(shù),必須首先分配一個H A N D L E數(shù)組,然后調(diào)用下面的函數(shù):

            HANDLE hHeaps[25];
            DWORD dwHeaps = GetProcessHeaps(25, hHeaps);
            if(dwHeaps > 5) 
            {
               //More heaps are in this process than we expected.
            } 
            else
            {
               //hHeaps[0] through hHeap[dwHeaps - 1]
               //identify the existing heaps.
            }

            注意,當(dāng)該函數(shù)返回時(shí),你的進(jìn)程的默認(rèn)堆棧的句柄也包含在堆棧句柄的數(shù)組中。

            H e a p Va l i d a t e函數(shù)用于驗(yàn)證堆棧的完整性:

            BOOL HeapValidate(
               HANDLE hHeap,
               DWORD fdwFlags,
               LPCVOID pvMem);

            調(diào)用該函數(shù)時(shí),通常要傳遞一個堆棧句柄,一個值為0的標(biāo)志(唯一的另一個合法標(biāo)志是H E A P _ N O _ S E R I A L I Z E),并且為p v M e m傳遞N U L L。然后,該函數(shù)將遍歷堆棧中的內(nèi)存塊以確保所有內(nèi)存塊都完好無損。為了使該函數(shù)運(yùn)行得更快,可以為參數(shù)p v M e m傳遞一個特定的內(nèi)存塊的地址。這樣做可使該函數(shù)只檢查單個內(nèi)存塊的有效性。

            若要合并地址中的空閑內(nèi)存塊并收回不包含已經(jīng)分配的地址內(nèi)存塊的存儲器頁面,可以調(diào)用下面的函數(shù):

            UINT HeapCompact(
               HANDLE hHeap,
               DWORD fdwFlags);
            

            通常情況下,可以為參數(shù)f d w F l a g s傳遞0,但是也可以傳遞H E A P _ N O _ S E R I A L I Z E。

            下面兩個函數(shù)H e a p L o c k和H e a p U n l o c k是結(jié)合在一起使用的:

            BOOL HeapLock(HANDLE hHeap);
            BOOL HeapUnlock(HANDLE hHeap);

            這些函數(shù)是用于線程同步的。當(dāng)調(diào)用H e a p L o c k函數(shù)時(shí),調(diào)用線程將成為特定堆棧的所有者。如果其他任何線程調(diào)用堆棧函數(shù)(設(shè)定相同的堆棧句柄),系統(tǒng)將暫停調(diào)用線程的運(yùn)行,并且在堆棧被H e a p U n l o c k函數(shù)解鎖之前不允許它醒來。

            H e a p A l l o c、H e a p S i z e和H e a p F r e e等函數(shù)在內(nèi)部調(diào)用H e a p L o c k和H e a p U n l o c k函數(shù)來確保對堆棧的訪問能夠順序進(jìn)行。自己調(diào)用H e a p L o c k或H e a p U n l o c k這種情況是不常見的。

            最后一個堆棧函數(shù)是H e a p Wa l k:

            BOOL HeapWalk(
               HANDLE hHeap,
               PPROCESS_HEAP_ENTRY pHeapEntry);

            該函數(shù)只用于調(diào)試目的。它使你能夠遍歷堆棧的內(nèi)容。可以多次調(diào)用該函數(shù)。

            zz


            posted on 2006-09-21 16:24 夢在天涯 閱讀(4349) 評論(0)  編輯 收藏 引用 所屬分類: Windows API

            公告

            EMail:itech001#126.com

            導(dǎo)航

            統(tǒng)計(jì)

            • 隨筆 - 461
            • 文章 - 4
            • 評論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1811117
            • 排名 - 5

            最新評論

            閱讀排行榜

            久久综合九色综合久99| 亚洲va久久久噜噜噜久久男同| 97久久精品人妻人人搡人人玩| 久久久久99精品成人片试看 | 97精品国产97久久久久久免费| 亚洲欧美日韩精品久久| 一本一道久久a久久精品综合| 国内精品久久久久久99| 久久精品中文字幕大胸| 久久精品国产99国产电影网 | 亚洲国产婷婷香蕉久久久久久| 亚洲综合久久久| 很黄很污的网站久久mimi色| 久久AV高潮AV无码AV| 久久99精品久久久久久野外| 久久婷婷五月综合色奶水99啪| 国内精品久久久久久中文字幕| 久久99精品国产自在现线小黄鸭| 天天影视色香欲综合久久| 久久777国产线看观看精品| 久久亚洲精品国产精品| 欧美日韩精品久久久免费观看 | 一本色道久久88精品综合 | 久久丝袜精品中文字幕| 国产精品久久自在自线观看| 久久国语露脸国产精品电影| 久久婷婷是五月综合色狠狠| 蜜臀久久99精品久久久久久| 国产精品伊人久久伊人电影 | 97精品国产97久久久久久免费| 思思久久99热免费精品6| 久久无码一区二区三区少妇| 国内精品久久久久影院网站| 久久99精品久久久久久噜噜| 久久精品国产清自在天天线| 久久精品一区二区影院 | 久久精品国产亚洲AV不卡| 少妇被又大又粗又爽毛片久久黑人| 久久久WWW成人免费毛片| 久久亚洲高清综合| 一本色综合久久|