閱讀374 返回首頁    go iPhone_iPad_Mac_apple


進一步理解C++中的堆(Heap)

最近的項目涉及到Heap Corruption的問題,所以對堆要有更深的理解。

進程初始化時會被分配一個默認大小為1M的默認堆,這個堆會被很多重要的函數調用,比如當我們調用ANSI版本的某些函數時,它們的Unicode版本字符串就會存於其中。若應用程序中有多個線程都用到了默認堆,那麼會有機製使得同時隻能有一線程能在默認堆中進行操作。默認堆的分配和銷毀都是由係統控製的,但是我們可以通過GetPreocessHeap()來得到本進程的默認堆句柄。

常用的分配函數有VirtualAlloc和HeapAlloc.VirtualAlloc請求4K為邊界的整塊虛擬內存,HeapAlloc分配任意大小的內存塊。但後者是依賴前者實現的。也就是說在操作係統的層麵上管理內存的最小單位是4K。要實現更小的內存管理(即HeapAlloc),需要用戶態的程序自己去分配,比如說Windows的HeapManager。在分配時先用分配足夠大的4K倍數的空間,再去進行內部的分配和回收。一般而言,對於小於1M的地址空間,我們一般使用HeapCreate(),但是更大的話,會傾向於用VirtualAlloc()在虛擬內存中分配。

以Alloc結尾的函數都隻是分配堆空間,而真正的要去創建一個堆,要使用HeapCreate()。HeapCreate()會返回一個新堆的句柄,而各種alloc函數可以利用這個句柄在不同的堆空間上進行內存分配。在不同的堆上進行alloc可以有效的避免內存碎片的問題,因為當某一個堆中的內容不再需要時,我們可以將這個堆整個的HeapDestroy()掉。但是,若各種數據都存於一個堆中,則要Destroy整個堆必須保證所有的數據都不再需要。

當我們先把一個地址空間HeapFree之後,若HeapManager沒有進行VirtualFree的操作,再次訪問該地址操作係統並不會報錯。因為以HeapFree和HeapAlloc都是由HeapManager來控製的,而操作係統一般情況下的界定粒度為4k。如果隻是在HeapManager的控製範圍內發生了越界,操作係統可能並不會認為這有什麼錯誤。(因為沒有在以4k為粒度的內存上越界)。

在各種create中,經常會有HEAP_NOSERIALIZE這個標誌,它的作用是對堆進行線程訪問控製。若這個標誌被加到參數中,那麼同一時刻,可以有多個線程對同一個堆進行堆操作。反之亦然。如果我們不用這個參數,還有兩個可用函數HeapLock()和HeapUnlock()達到類似效果。

最後更新:2017-04-03 12:56:32

  上一篇:go 【轉】【Android】開源項目匯總-備用
  下一篇:go cocos2d-x讀取xml(適用於cocos2d-x 2.0以上版本)