日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

內(nèi)存管理[3]

 獨孤求財 2012-03-30
VirtualAlloc 分配的內(nèi)存是以 4K 為最小單位、連續(xù)的內(nèi)存地址(但映射到真實的內(nèi)存時它不一定是連續(xù)的), 前面說了, 它不適合分配小內(nèi)存(譬如只有幾個字節(jié)的變量); 局部的變量在 "棧" 中有程序自動管理, 那么那些全局的小變量怎么辦呢? 這就要用到 "堆".

這樣看來, VirtualAlloc 分配的內(nèi)存既不是 "棧" 也不是 "堆"; VirtualAlloc 分配的內(nèi)存地址是連續(xù)的, "堆" 中內(nèi)容一般是不連續(xù)的, 所以管理 "堆" 比較麻煩, 它是通過雙線鏈表的結(jié)構(gòu)方式管理的; 程序可以擁有若干個 "堆", 每一個 "堆" 都會有一個句柄, 訪問 "堆" 中的內(nèi)容時先要找到這個 "堆", 然后再遍歷鏈表, 這可能就是 "堆" 比 "棧" 慢的根本原因.

在 "堆" 中分配內(nèi)存(HeapAlloc)前先要建立 "堆"(HeapCreate), 就像程序有默認的 "棧" 一樣, 每一個程序都有一個默認建立的 "堆"(可以用 GetProcessHeap 獲取這個 "默認堆" 的句柄), 我們在 Delphi 中用到 "堆" 時, 使用的就是這個 "默認堆". 如果讓程序更靈活地擁有多個 "堆", 必須要用到 API 函數(shù).

建立 "堆" 時會同時提交真實內(nèi)存的, 這在申請大內(nèi)存時會很慢, 所以默認堆也只有 1M, 但 "默認堆" 并沒有限制大小, 它會根據(jù)需要動態(tài)增長.

有了 "默認堆" 還有必要申請其他的 "堆" 嗎? 這只有在多線程中才能體現(xiàn)出來, 和 "棧" 不一樣, 程序會給每個線程分配一個 "棧區(qū)"; 而 "默認堆" 是進程中的所有線程公用的, 當一個線程使用 "默認堆" 時, 另一個需要使用 "堆" 的線程就要先掛起等待, 也就是它們不能同時使用; 只有通過 API 函數(shù)重新建立的私有堆才是互不干涉、最有效率的.

先了解一下 "堆" 相關(guān)的函數(shù).
//建立堆; 注意建立時指定的尺寸也是按頁大小(PageSize)對齊的, 譬如指定 15k, 實際會分配 16K.
HeapCreate(
  flOptions: DWORD;     {堆屬性選項, 見下表}
  dwInitialSize: DWORD; {初始尺寸, 單位是字節(jié); 該大小會被直接提交到實際的內(nèi)存}
  dwMaximumSize: DWORD  {最大尺寸, 如果不限定最大值就設(shè)為 0}
): THandle;             {返回堆句柄; 失敗返回 0, 但如果參數(shù) flOptions 允許了異常, 失敗會返回異常標識}

//flOptions 參數(shù)可選值:
HEAP_NO_SERIALIZE        = 1; {非互斥, 此標記可允許多個線程同時訪問此堆}
HEAP_GENERATE_EXCEPTIONS = 4; {當建立堆出錯時, 此標記可激發(fā)一個異常并返回異常標識}
HEAP_ZERO_MEMORY         = 8; {把分配的內(nèi)存初始化為 0}

//flOptions 參數(shù)指定有 HEAP_GENERATE_EXCEPTIONS 時, 可能返回的異常:
STATUS_ACCESS_VIOLATION = DWORD($C0000005); {參數(shù)錯誤}
STATUS_NO_MEMORY        = DWORD($C0000017); {內(nèi)存不足}

//銷毀堆 HeapDestroy( hHeap: THandle {堆句柄} ): BOOL;      {}
//從堆中申請內(nèi)存 HeapAlloc(   hHeap: THandle; {堆句柄}   dwFlags: DWORD; {內(nèi)存屬性選項, 見下表}   dwBytes: DWORD  {申請內(nèi)存的大小, 單位是字節(jié)} ): Pointer;      {返回內(nèi)存指針; 失敗返回 0 或異常, 情況和建立堆是一樣} //dwFlags 參數(shù)可選值: HEAP_NO_SERIALIZE        = 1; {非互斥, 此標記可允許多個線程同時訪問此堆} HEAP_GENERATE_EXCEPTIONS = 4; {當建立堆出錯時, 此標記可激發(fā)一個異常并返回異常標識} HEAP_ZERO_MEMORY        = 8; {把分配的內(nèi)存初始化為 0} {能看出這和堆的屬性選項是一樣的; 如果 dwFlags 參數(shù)設(shè)為 0, 將使用堆的屬性; 如果重新指定將覆蓋堆的屬性} {另外: 如果堆是默認堆, 也就是堆句柄來自 GetProcessHeap, dwFlags 參數(shù)會被忽略}
//改變堆內(nèi)存的大小, 也就是重新分配 HeapReAlloc(   hHeap: THandle; {句柄}   dwFlags: DWORD; {內(nèi)存屬性選項; 該參數(shù)比 HeapAlloc 多出一個選項, 見下表}   lpMem: Pointer; {原內(nèi)存指針}   dwBytes: DWORD  {新的尺寸} ): Pointer;      {同 HeapAlloc} //dwFlags 參數(shù)可選值: HEAP_NO_SERIALIZE          = 1{非互斥, 此標記可允許多個線程同時訪問此堆} HEAP_GENERATE_EXCEPTIONS  = 4{當建立堆出錯時, 此標記可激發(fā)一個異常并返回異常標識} HEAP_ZERO_MEMORY          = 8{把分配的內(nèi)存初始化為 0} HEAP_REALLOC_IN_PLACE_ONLY = 16; {此標記不允許改變原來的內(nèi)存位置}
//獲取堆中某塊內(nèi)存的大小 HeapSize(   hHeap: THandle; {堆句柄}   dwFlags: DWORD; {內(nèi)存屬性; 可選值是 0 或 HEAP_NO_SERIALIZE, 后者可確保同步訪問}   lpMem: Pointer  {內(nèi)存指針} ): DWORD;        {成功返回字節(jié)為單位的大小; 失敗返回 $FFFFFFFF}
//釋放堆中指定的內(nèi)存塊 HeapFree(   hHeap: THandle; {堆句柄}   dwFlags: DWORD; {內(nèi)存屬性; 可選值是 0 或 HEAP_NO_SERIALIZE}   lpMem: Pointer  {內(nèi)存指針} ): BOOL;          {}
//驗證堆 HeapValidate(   hHeap: THandle; {}   dwFlags: DWORD; {}   lpMem: Pointer  {} ): BOOL;          {}
//整理堆 HeapCompact(   hHeap: THandle; {}   dwFlags: DWORD  {} ): UINT;          {}
//鎖定堆 HeapLock(   hHeap: THandle {} ): BOOL;        {}
//鎖定后的解鎖 HeapUnlock(   hHeap: THandle {} ): BOOL;        {}
//列舉堆中的內(nèi)存塊 HeapWalk(   hHeap: THandle;                {}   var lpEntry: TProcessHeapEntry {} ): BOOL;                        {}
舉例放下篇吧.

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多