程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 內存管理[3]

內存管理[3]

編輯:Delphi

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

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

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

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

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

先了解一下 "堆" 相關的函數.//建立堆; 注意建立時指定的尺寸也是按頁大小(PageSize)對齊的, 譬如指定 15k, 實際會分配 16K.
HeapCreate(
 flOptions: DWord;   {堆屬性選項, 見下表}
 dwInitialSize: DWord; {初始尺寸, 單位是字節; 該大小會被直接提交到實際的內存}
 dwMaximumSize: DWord {最大尺寸, 如果不限定最大值就設為 0}
): THandle;       {返回堆句柄; 失敗返回 0, 但如果參數 flOptions 允許了異常, 失敗會返回異常標識}
//flOptions 參數可選值:
HEAP_NO_SERIALIZE    = 1; {非互斥, 此標記可允許多個線程同時訪問此堆}
HEAP_GENERATE_EXCEPTIONS = 4; {當建立堆出錯時, 此標記可激發一個異常並返回異常標識}
HEAP_ZERO_MEMORY     = 8; {把分配的內存初始化為 0}
//flOptions 參數指定有 HEAP_GENERATE_EXCEPTIONS 時, 可能返回的異常:
STATUS_Access_VIOLATION = DWord($C0000005); {參數錯誤}
STATUS_NO_MEMORY    = DWord($C0000017); {內存不足}
//銷毀堆
HeapDestroy(
hHeap: THandle {堆句柄}
): BOOL;    {}
//從堆中申請內存
HeapAlloc(
 hHeap: THandle; {堆句柄}
 dwFlags: DWord; {內存屬性選項, 見下表}
 dwBytes: DWord {申請內存的大小, 單位是字節}
): Pointer;    {返回內存指針; 失敗返回 0 或異常, 情況和建立堆是一樣}
//dwFlags 參數可選值:
HEAP_NO_SERIALIZE    = 1; {非互斥, 此標記可允許多個線程同時訪問此堆}
HEAP_GENERATE_EXCEPTIONS = 4; {當建立堆出錯時, 此標記可激發一個異常並返回異常標識}
HEAP_ZERO_MEMORY     = 8; {把分配的內存初始化為 0}
{能看出這和堆的屬性選項是一樣的; 如果 dwFlags 參數設為 0, 將使用堆的屬性; 如果重新指定將覆蓋堆的屬性}
{另外: 如果堆是默認堆, 也就是堆句柄來自 GetProcessHeap, dwFlags 參數會被忽略}
//改變堆內存的大小, 也就是重新分配
HeapReAlloc(
 hHeap: THandle; {句柄}
 dwFlags: DWord; {內存屬性選項; 該參數比 HeapAlloc 多出一個選項, 見下表}
 lpMem: Pointer; {原內存指針}
 dwBytes: DWord {新的尺寸}
): Pointer;    {同 HeapAlloc}
//dwFlags 參數可選值:
HEAP_NO_SERIALIZE     = 1; {非互斥, 此標記可允許多個線程同時訪問此堆}
HEAP_GENERATE_EXCEPTIONS  = 4; {當建立堆出錯時, 此標記可激發一個異常並返回異常標識}
HEAP_ZERO_MEMORY      = 8; {把分配的內存初始化為 0}
HEAP_REALLOC_IN_PLACE_ONLY = 16; {此標記不允許改變原來的內存位置}
//獲取堆中某塊內存的大小
HeapSize(
 hHeap: THandle; {堆句柄}
 dwFlags: DWord; {內存屬性; 可選值是 0 或 HEAP_NO_SERIALIZE, 後者可確保同步訪問}
 lpMem: Pointer {內存指針}
): DWord;     {成功返回字節為單位的大小; 失敗返回 $FFFFFFFF}
//釋放堆中指定的內存塊
HeapFree(
 hHeap: THandle; {堆句柄}
 dwFlags: DWord; {內存屬性; 可選值是 0 或 HEAP_NO_SERIALIZE}
 lpMem: Pointer {內存指針}
): BOOL;     {}
//驗證堆
HeapValidate(
 hHeap: THandle; {}
 dwFlags: DWord; {}
 lpMem: Pointer {}
): BOOL;     {}
//整理堆
HeapCompact(
 hHeap: THandle; {}
 dwFlags: DWord {}
): UINT;     {}
//鎖定堆
HeapLock(
 hHeap: THandle {}
): BOOL;     {}
//鎖定後的解鎖
HeapUnlock(
 hHeap: THandle {}
): BOOL;     {}
//列舉堆中的內存塊
HeapWalk(
 hHeap: THandle;        {}
 var lpEntry: TProcessHeapEntry {}
): BOOL;             {}
舉例放下篇吧.



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved