二、堆管理
使用者使用記憶體配置函數分配的記憶體都位於堆中,所以使用堆管理函數對記憶體進行分配、釋放等是最為直接的方式。
Windows系統中,每個進程都有自己的堆,每個進程的堆的數量也有所不同。Windows系統中所謂的“堆”(Heap)並不是記憶體塊,而是一種用於記憶體管理的對象,也是一種記憶體組織的形式。進程可以從屬於自己的堆上分配記憶體和釋放記憶體。堆包括有若干種屬性,如堆的大小最大值可以是固定的、也可以是“可增長的”;堆上的資料內容是否可以作為代碼可執行;堆是否可串連存取等。
三、全域和局部記憶體管理
32位Windows系統中並沒有區分全域堆和局部堆,Windows系統中之所以還存在著全域和局部函數的概念是為了和16位系統相相容。GlobalAlloc、LocalAlloc函數所分配的記憶體沒有什麼區別,記憶體配置的效果與HeapAlloc函數類似。但是GlobalAlloc與LocalAlloc分配記憶體時比HeapAlloc要慢。
因此更推薦使用Heap函數。
四、虛擬記憶體管理
記憶體管理的原理都由系統的記憶體管理器實現,應用程式只能管理屬性於自己的虛擬位址空間。
進程的虛擬位址空間記憶體頁面存在3種狀態,分別為空白閑的(free)、保留的(reserved)和提交的(Committed)。
五、記憶體配置的比較
使用VirtualAlloc,VirtualFree等函數進行操作,其操作的基本單位是記憶體頁面。
HeapAlloc、GlobalAlloc、LoaclAlloc在功能上沒有大的區別,都是在堆中分配記憶體,分配的記憶體不需要進行頁對齊,也不用關心分頁機制、頁面狀態、頁面屬性等內容。HeapAlloc是程式在需要分配記憶體時最直接的方式。這些內容由堆管理器負責。
堆記憶體管理依賴於虛擬記憶體管理。在建立堆時,HeapCreate API函數會向系統請求虛擬記憶體分頁,之後在這個堆上的記憶體配置實際上是在從虛擬記憶體管理中擷取的記憶體分頁上再分配大小任意的記憶體塊,如果在建立堆時指定了固定了堆大小,那麼在堆上分配記憶體塊時,其範圍不能超過設定的堆大小,堆大小一定是記憶體頁大小的整數倍。如果在建立堆時不固定堆的大小,堆管理函數會根據分配的請求數量,動態地向虛擬內容管理函數請求記憶體分頁。
VirtualAlloc的功能是對進程虛擬位址空間中記憶體分頁的狀態進行管理,屬於虛擬記憶體管理(以記憶體頁面為單位)的範圍。當然記憶體的分配也是通過改變虛擬記憶體頁面屬性來實現的,所以VirtualAlloc間接達到了分配記憶體的目的。堆管理器也是依賴於虛擬記憶體管理的,在收到HeapAlloc的記憶體配置的請求時,堆管理器會根據情況決定是否使用虛擬記憶體管理機制分配新的頁面,以及如何在頁面上布局分配的記憶體塊,從這個層次上講VirtualAlloc更為底層。
實際上只要虛擬記憶體管理函數將頁面屬性設定為“已提交”後,就可以在之上進行讀寫等操作。
堆管理函數為應用程式提供了一種更靈活、更簡單的方式來管理這些“已提交”的記憶體。其好處一是分配更簡單,二是可以分配任意大小的記憶體,三是不用直接與複製的記憶體分頁機制打交道。
標準C函數的記憶體配置函數則直接使用了HeapAlloc。
HeapAlloc、GlobalAlloc、LoaclAlloc在32位系統上功能上是一致的,但是由於Globa]_Alloc、LoaclAlloc需要相容16位系統,所需進行的判斷和處理會更多,因此GlobalAlloc、LoaclAlloc較HeapAlloc效率低。當然標準C函數malloc也是調用HeapAlloc實現的,所以其效率也必然比HeapAlloc低。
由於HeapAlloc與VirtualAlloc功能定位上的不同,所以在效率上沒有可比性。從原理上講,HeapAlloc在分配記憶體時,如果堆管理器中有足夠的已提交的頁面可以使用,那麼它不需要將記憶體分頁從其他狀態改變為已提交狀態,只需要在堆管理器中進行相關管理;如果在分配時沒有足夠的已提交頁面供使用,那麼還需要將虛擬記憶體分頁從其他狀態改變為已提交狀態,在有足夠的可使用的已提交頁面的情況下,再由堆管理器進行相關管理。