国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

保持C/C++程序代碼的可伸縮性

2019-11-17 05:02:27
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  在今天,已有許多的32位應(yīng)用程序感到,在32位平臺(tái)上可用的虛擬內(nèi)存受到了一定的限制,對(duì)程序開(kāi)發(fā)者來(lái)說(shuō),即使是開(kāi)始關(guān)注64位平臺(tái)時(shí),也不得不維護(hù)軟件的32位版本,這就需要一種方法,以使代碼的兩個(gè)版本都保持相當(dāng)?shù)目缮炜s性。

  目前的內(nèi)存剖析工具能幫助確定,當(dāng)程序達(dá)到峰值內(nèi)存使用量時(shí),都發(fā)生了什么,但是這些工具都過(guò)于關(guān)注已分配的內(nèi)存塊,而不是已提交的虛擬內(nèi)存地址空間,而這兩種衡量標(biāo)準(zhǔn)沒(méi)有直接的相關(guān)性,如內(nèi)存泄漏、內(nèi)存碎片、內(nèi)存塊內(nèi)的空間浪費(fèi)、或過(guò)度延遲的內(nèi)存單元重新分配這些因素,都會(huì)導(dǎo)致不必要的虛擬內(nèi)存提交。運(yùn)行時(shí)分析工具如IBM Rational Purify或Parasoft Inuse均可以提供內(nèi)存泄漏及已用內(nèi)存的描述,這些信息是非常有用的,但是,一個(gè)非凡的內(nèi)存塊也許可能、也許不可能影響到虛擬內(nèi)存覆蓋區(qū),另外,甚至一個(gè)有碎片的內(nèi)存堆中的一個(gè)小塊,也能直接影響到虛擬內(nèi)存覆蓋區(qū)。從另一方面來(lái)說(shuō),在此范圍內(nèi)的任意內(nèi)存塊--甚至泄漏的塊,對(duì)虛擬內(nèi)存覆蓋區(qū)來(lái)說(shuō),也不會(huì)與之有什么關(guān)系,除非每一個(gè)此范圍內(nèi)有用的內(nèi)存塊能重新分配到一個(gè)更緊湊的范圍內(nèi),這就有點(diǎn)像java或托管程序的垃圾回收機(jī)制,但對(duì)大多數(shù)C/C++本地應(yīng)用程序來(lái)說(shuō),就絕對(duì)不可能了,因?yàn)樵谔摂M內(nèi)存空間中,它們內(nèi)存塊的位置是不確定的。

  至于本地代碼,不必要的虛擬內(nèi)存使用,這個(gè)實(shí)際的問(wèn)題,比未清理的內(nèi)存塊這個(gè)理論上的問(wèn)題,更加有實(shí)質(zhì)性。未清理的內(nèi)存塊可能導(dǎo)致虛擬內(nèi)存的浪費(fèi),造成過(guò)多的系統(tǒng)開(kāi)銷,但或者不會(huì);這完全依靠于堆治理器是否提交了更多的虛擬內(nèi)存,以支撐這種浪費(fèi)。某些很小的未使用的內(nèi)存塊,不會(huì)引起不必要的堆"擴(kuò)展"。與其讓你來(lái)猜哪一個(gè)或多少已浪費(fèi)的內(nèi)存塊導(dǎo)致了堆擴(kuò)展,倒不如學(xué)會(huì)怎樣判定出有意義的浪費(fèi)是什么。當(dāng)堆中包含不再使用的內(nèi)存塊時(shí),此時(shí)通過(guò)加入對(duì)未縮減堆的檢查,就能確定出與你的程序虛擬內(nèi)存要求有很大關(guān)系的、必須進(jìn)行的內(nèi)存塊清理。

  為找出哪一個(gè)堆中的內(nèi)存塊需多留意,必須在程序中加入一些額外的代碼,以跟蹤內(nèi)存堆范圍及已分配的內(nèi)存塊。對(duì)額外的代碼進(jìn)行條件編譯,生成一個(gè)特定的版本,也許是一個(gè)不錯(cuò)的辦法。

  為達(dá)到此目的,需編寫(xiě)自定義的內(nèi)存分配例程,并跟蹤每一個(gè)內(nèi)存塊,另有一個(gè)自定義的釋放例程,且跟蹤虛擬內(nèi)存中堆的位置,請(qǐng)參見(jiàn)例1與例2的偽代碼算法。可能還需編寫(xiě)自定義的訪問(wèn)函數(shù)以標(biāo)記出訪問(wèn)過(guò)的內(nèi)存塊,以便于在適當(dāng)?shù)臅r(shí)候釋放虛擬內(nèi)存,所有這些并不需要過(guò)多的內(nèi)存開(kāi)銷。另一方面,假如你的程序以堆的形式使用了大量的內(nèi)存,那么將會(huì)極大地降低性能,此處的方法也不是長(zhǎng)久之計(jì)。

  例1:

/* 輸入?yún)?shù)*/
ADDRESS triggerAddr
SIZE triggerSize
LIST a list of tracked heap ranges

IF (the virtual memory at triggerAddr is tracked on the list as part of a heap range)
DO
IF (triggerAddr + triggerSize >
(the tracked upper boundary of that heap range))
DO
/* 一個(gè)現(xiàn)有的堆范圍被擴(kuò)展 */

make system call(s) to determine the base and extent of the newly committed range that contains the addresses from triggerAddr to (triggerAddr + triggerSize)

update the size of the tracked heap range to indicate its new upper limit
END
END
ELSE DO
/* 在triggerAddr中有一個(gè)新的堆范圍 */

make system call(s) to determine the base and extent of the newly committed range that contains the addresses from triggerAddr to (triggerAddr + triggerSize)

track the new committed range in the list of heap ranges
END
  例2:

/* 輸入?yún)?shù) */
ADDRESS triggerAddr
SIZE triggerSize
LIST a list of tracked heap ranges

/* 局部變量 */
ADDRESS origRangeBase
SIZE origRangeSize
BOOL bFoundChange

bFoundChange = FALSE

IF (the virtual memory at triggerAddr is not tracked on the heap range list as part of a heap range)
DO
/*似乎我們已經(jīng)清楚此次釋放了。*/
END
ELSE IF (an access exception occurs when memory at triggerAddr is read)
DO
bFoundChange = TRUE
END

IF (bFoundChange) DO
/*因?yàn)橹皟?nèi)存塊占用的空間被釋放了,所以堆占用的虛擬內(nèi)存范圍就改變了。*/

make system calls to determine the bases and extents of the tracked committed heap ranges in the immediate vicinity of the decommitted range that includes the addresses from triggerAddr to (triggerAddr + triggerSize)

/*更新堆范圍跟蹤,以反映剩余提交的范圍 */

IF (any portion of the tracked heap range that contained the block at TriggerAddr is still committed)
DO
update the heap range list to track just the portion(s) of that range that remain committed
END
ELSE
DO
delete the list element that tracks the range
END
END QQread.com 推出Windows2003教程 win2003安裝介紹 win2003網(wǎng)絡(luò)優(yōu)化 win2003使用技巧 win2003系統(tǒng)故障 服務(wù)器配置 專家答疑
更多的請(qǐng)看:http://www.qqread.com/windows/2003/index.Html跟蹤堆內(nèi)存塊

  可使用自定義的內(nèi)存分配函數(shù)來(lái)進(jìn)行內(nèi)存塊的跟蹤,而這種函數(shù)最初被稱為普通內(nèi)存分配函數(shù),舉例來(lái)說(shuō),C語(yǔ)言程序中一般使用malloc(),爾后,自定義的內(nèi)存分配會(huì)進(jìn)行以下一系列的操作:

  ·在目前已分配的內(nèi)存塊列表中,跟蹤新分配的內(nèi)存塊。

  ·決定是否向系統(tǒng)提交虛擬內(nèi)存。

  ·假如虛擬內(nèi)存已被提交,跟蹤包含此內(nèi)存塊的堆范圍,并更新上述堆內(nèi)存塊列表,以標(biāo)識(shí)出從未被訪問(wèn)過(guò)的內(nèi)存塊。

  還需要自定義的釋放與重分配內(nèi)存函數(shù),以便通過(guò)程序中使用的內(nèi)存塊的地址與大小,來(lái)更新內(nèi)存塊列表。所跟蹤的堆內(nèi)存塊列表應(yīng)包含如下結(jié)構(gòu):

  ·內(nèi)存塊的基地址。

  ·自身大小

  ·用于指示自從上次虛擬內(nèi)存被提交之后,內(nèi)存塊是否被訪問(wèn)過(guò)的布爾值。

  當(dāng)一個(gè)內(nèi)存塊被釋放后,自定義的釋放代碼將會(huì)進(jìn)行以下操作:

  ·假如自從上次堆擴(kuò)展之后,內(nèi)存塊還未被訪問(wèn)過(guò),將向程序報(bào)告。

  ·從列表中刪除跟蹤的內(nèi)存塊。

  ·判定系統(tǒng)是否已釋放了包含此內(nèi)存塊的虛擬內(nèi)存。

  ·假如虛擬內(nèi)存被釋放,要相應(yīng)地更新,以反映剩余的堆范圍。

  當(dāng)一個(gè)內(nèi)存塊被重新分配時(shí),你的自定義重新分配內(nèi)存代碼必須進(jìn)行以下兩種操作:首先,在釋放之后重新跟蹤內(nèi)存塊,因?yàn)橹匦路峙涞膬?nèi)存塊可能不在原位置;其次,在分配之后也要重新跟蹤新的基地址及分配內(nèi)存塊的大小。另有一個(gè)可選的方法,你可檢查是否重新分配的內(nèi)存塊被移動(dòng)了,假如沒(méi)有被移動(dòng),只需僅僅更新內(nèi)存塊跟蹤列表,標(biāo)出此內(nèi)存塊的大小;假如內(nèi)存塊還在同一基地址,但是增長(zhǎng)了,此時(shí)就要檢查堆擴(kuò)展,并按照前述分配內(nèi)存的方法重來(lái)一遍。

  跟蹤堆自身

  堆跟蹤取決于當(dāng)內(nèi)存塊被分配或釋放時(shí),虛擬內(nèi)存是否分別被提交或釋放,依此可以建立一張堆內(nèi)存范圍跟蹤表,以確定在程序運(yùn)行期間,虛擬內(nèi)存空間中堆的確切位置,跟蹤列表中應(yīng)包括如下數(shù)據(jù):

  ·跟蹤范圍的基地址

  ·自身大小

  在Windows操作系統(tǒng)中,這些值可通過(guò)HeapWalk()調(diào)用獲得,此處要注重的是,HeapWalk()函數(shù)調(diào)用開(kāi)銷巨大,因此,只在程序需要時(shí)調(diào)用,而不是當(dāng)有內(nèi)存分配或釋放時(shí)都調(diào)用。另一種Windows上的方法是使用IsBadReadPointer()函數(shù),當(dāng)一個(gè)內(nèi)存塊被釋放后,你可以調(diào)用這個(gè)函數(shù)快速地判定包含此內(nèi)存塊的虛擬內(nèi)存是否已被釋放。另一個(gè)可以跨平臺(tái)的備選方法是,可試著訪問(wèn)包含此內(nèi)存塊的虛擬內(nèi)存,并捕捉可能發(fā)生的訪問(wèn)異常。此外,只有在一種情況下會(huì)考慮使用如HeapWalk()這樣開(kāi)銷巨大的函數(shù),就是需判定鄰近剩余的已提交堆范圍。

  通過(guò)一種探測(cè)堆內(nèi)存提交的算法,堆內(nèi)存跟蹤列表會(huì)不斷地增長(zhǎng),如例1中所示。要注重的是,當(dāng)你的程序分配一個(gè)內(nèi)存塊時(shí),自定義的內(nèi)存分配代碼也能跟蹤到這些內(nèi)存塊,并使用例1中的算法來(lái)更新包含內(nèi)存塊的堆列表。假如一個(gè)內(nèi)存塊的分配導(dǎo)致了額外的虛擬內(nèi)存被提交,那么被內(nèi)存塊占用的虛擬內(nèi)存會(huì)在之前就釋放,或許之前就被用作別的用途。在任一情況中,必須有條件地更新堆范圍跟蹤列表: l 假如正在跟蹤已提交范圍的基地址,此時(shí)必須更新范圍的大小,以指示出新的范圍上限。

  ·否則,必須建立一張新的堆內(nèi)存范圍跟蹤表。

  假如一個(gè)新的內(nèi)存塊出現(xiàn)在一個(gè)之前未被跟蹤的堆范圍中,就滿足了以上條件,此時(shí)明智地使用前述的系統(tǒng)調(diào)用可高效地跟蹤堆內(nèi)存范圍。

  當(dāng)你的程序釋放一個(gè)內(nèi)存塊時(shí),自定義的內(nèi)存釋放代碼會(huì)使用到如例2中的算法,此算法會(huì)先判定釋放的內(nèi)存是否與被跟蹤的堆內(nèi)存范圍有關(guān);接下來(lái),必須檢查已釋放內(nèi)存塊占用的空間是否仍處于提交狀態(tài),假如是,表明了即使內(nèi)存塊被釋放,虛擬內(nèi)存的覆蓋區(qū)也沒(méi)有發(fā)生改變,否則,你的代碼必須進(jìn)行如例2結(jié)尾處的系統(tǒng)調(diào)用--如Windows中的HeapWalk()--以確保跟蹤的堆是最新的,且包含堆內(nèi)存塊的虛擬內(nèi)存已被釋放。

  假如虛擬內(nèi)存已經(jīng)被提交,那么你應(yīng)該檢查那些通常包含了最近被釋放的堆內(nèi)存塊的內(nèi)存范圍,以確認(rèn)是否有此范圍內(nèi)的內(nèi)存被提交,而此范圍內(nèi)任何被提交的內(nèi)存部分都應(yīng)該是在一個(gè)堆內(nèi)存范圍內(nèi),非凡是假如它包含了跟蹤列表上的內(nèi)存塊,進(jìn)行此檢查可保證進(jìn)一步的準(zhǔn)確性。接下來(lái)還有以下兩件事,如例2中所示:

  ·假如被跟蹤的堆內(nèi)存范圍內(nèi)任一部分被提交,必須更新你的跟蹤列表。

  ·否則,刪除列表中的元素并跟蹤新的范圍。

  假如提交的部分在中間,那么就有可能把堆內(nèi)存范圍截成好幾斷,總而言之,在你放棄跟蹤老的范圍之前,應(yīng)先在全范圍內(nèi)檢查一下哪一部分仍處于提交狀態(tài)。

  程序中可能會(huì)用到好幾個(gè)不同的堆,在Windows上,假如你調(diào)用HeapCreate()并把返回的句柄傳給接下來(lái)的HeapAlloc()、Hea
  一些專業(yè)的運(yùn)行時(shí)分析工具也能對(duì)分配的內(nèi)存塊及堆范圍進(jìn)行跟蹤,就像前面所說(shuō)的自定義內(nèi)存分配函數(shù)與釋放函數(shù)一樣,甚至還能通過(guò)基本的虛擬內(nèi)存HASH值(ox187d690)進(jìn)一步跟蹤,以便為精確的運(yùn)行時(shí)錯(cuò)誤檢測(cè)提供更加可靠的手段。但此處描述的方法并不足以幫助你理解何時(shí)才能找到通過(guò)程序可控制的堆內(nèi)存塊,減少虛擬內(nèi)存消耗的時(shí)機(jī)。

  找到適當(dāng)?shù)那謇頃r(shí)機(jī)

  為使用跟蹤信息以精確定位那些導(dǎo)致虛擬內(nèi)存不必要增長(zhǎng)的堆內(nèi)存塊,你還必須要記錄下內(nèi)存訪問(wèn)動(dòng)作,并在程序讀寫(xiě)堆內(nèi)存時(shí),標(biāo)記出相應(yīng)的內(nèi)存塊跟蹤結(jié)構(gòu)。
假如你的堆內(nèi)存塊都是通過(guò)存取函數(shù)訪問(wèn)的,那么很輕易就可找到所有代碼讀寫(xiě)的內(nèi)存部分,并以條件編譯生成一個(gè)特定的版本。這些存取函數(shù)可查找你列表上被訪問(wèn)過(guò)的內(nèi)存塊,并設(shè)置布爾值作出標(biāo)記。

  當(dāng)虛擬內(nèi)存被提交生成一個(gè)堆,你的自定義內(nèi)存分配函數(shù)應(yīng)取消堆中所有內(nèi)存塊的標(biāo)記,而在接下來(lái),它們可能會(huì)重新被標(biāo)記上,一個(gè)接一個(gè),就像你的程序正在訪問(wèn)它們。當(dāng)一個(gè)取消標(biāo)記的內(nèi)存塊被釋放時(shí),相應(yīng)的虛擬內(nèi)存也會(huì)被釋放,此時(shí)你自定義的釋放函數(shù)就會(huì)先一步釋放內(nèi)存塊,以減小虛擬內(nèi)存的覆蓋范圍。

  也可安排對(duì)堆內(nèi)存塊作一些臨時(shí)的掃描,這也許可在每一次虛擬內(nèi)存提交時(shí)進(jìn)行。假如一個(gè)內(nèi)存塊在經(jīng)過(guò)多遍掃描后仍保持未標(biāo)記狀態(tài)(也許會(huì)花很長(zhǎng)時(shí)間),則包含此內(nèi)存塊的虛擬內(nèi)存范圍就必須對(duì)所跟蹤的內(nèi)存塊數(shù)進(jìn)行檢查。假如那個(gè)內(nèi)存塊,或者一組被忽視的類似內(nèi)存塊,只是單獨(dú)地與提交的虛擬內(nèi)存有關(guān)系,那么通過(guò)釋放與重新定位這些內(nèi)存塊,你可能已經(jīng)找到一個(gè)減少程序虛擬內(nèi)存要求的好方法。

  假如你實(shí)現(xiàn)了此處描述的所有內(nèi)存塊和堆范圍跟蹤代碼,而當(dāng)這些所有的跟蹤都起作用時(shí),那么程序的速度將會(huì)變得很慢,主要是因?yàn)樵诿恳淮味褍?nèi)存訪問(wèn)時(shí),都會(huì)進(jìn)行一遍列表查找,當(dāng)然,也可以通過(guò)一些快速列表查找方法如二分法查找、跳躍查找之類的來(lái)縮短查找的時(shí)間,還可使用對(duì)應(yīng)每個(gè)堆的單獨(dú)列表來(lái)加速查找。假如程序使用了許多的堆內(nèi)存塊,并且也找到了減少額外虛擬內(nèi)存消耗的方法,以往所花費(fèi)的所有精力與耐心,與此時(shí)得到的回報(bào)相比,就算不上什么了。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 东阳市| 永川市| 当阳市| 郎溪县| 尚义县| 台州市| 景泰县| 开阳县| 呼玛县| 札达县| 长岭县| 蒙山县| 牟定县| 那坡县| 闸北区| 上林县| 南溪县| 会昌县| 芜湖市| 合作市| 绥江县| 德清县| 礼泉县| 隆安县| 弥渡县| 东乌珠穆沁旗| 紫阳县| 自贡市| 吉林市| 镇雄县| 保德县| 哈尔滨市| 丹棱县| 乌恰县| 沙田区| 会宁县| 洪泽县| 玉田县| 苏尼特左旗| 淮阳县| 鹿泉市|