最近去了一次面試,面試官問道這個程序的自建堆和預設堆的相關問題,我當時感覺答的並不是很好,這時候我決定好好整理一下相關知識跟大家分享。
程序預設堆:
windows許多重要的函式都用unicode字元和unicode字串來執行它們所有的操作。如果我們呼叫的是乙個函式的ansi版本,那麼該函式的ansi版本必須把ansi字串轉換為unicode字串,然後再呼叫同乙個函式的unicode版本。為了轉換字串,ansi版本的函式需要分配一塊記憶體來儲存unicode版本的字串,這塊記憶體就是從程序的預設堆中分配的。預設堆大小一般為1m,可以在編譯器設定/heap。
程序自建堆:
為什麼要建立額外的堆:
1.對元件進行有效的保護
2.更有效的記憶體管理
3.使記憶體訪問區域性化
4.避免執行緒的同步開銷
5.快速釋放
1.對元件進行保護
舉個栗子:有乙個鍊錶和乙個二叉樹都需要儲存在同乙個堆中,這會使兩種結構混合,假如鍊錶中的某個節點出錯覆蓋他下邊的某塊記憶體,就可能把二叉樹結構破壞,這會導致定位出錯很難,於是把兩種結構放到兩個堆中,這種可能性就會小很多。
2.更有效的記憶體管理:
每個堆保證相同的結構會使記憶體分配更為合理。再舉上乙個栗子,鍊錶每個節點大小為24位元組,二叉樹每個節點32位元組,現在鍊錶釋放了2個節點,這時有了48位元組的空間,但是很有可能這兩塊記憶體不連續。而沒法給二叉樹分配乙個節點的空間。如此操作,會使堆內記憶體碎片化。
3.使記憶體訪問區域性化
我們知道系統在訪問記憶體的時候會產生頁交換,當系統把乙個記憶體頁換入到磁碟中,再從磁碟中換出乙個記憶體頁時,這種消耗是十分巨大的。於是,把相同的節點放在乙個記憶體堆中就顯得尤為重要了。繼續舉栗子,當我們乙個堆中只儲存鍊錶節點,或者只儲存二叉樹節點,這個時候記憶體很有可能分配到鄰近一塊兒記憶體中,這時候我們遍歷節點就不需要再進行頁交換了。但是兩個結構混用的話,很有可能看似相鄰的兩個節點其實在兩個頁交換檔案中,如果運氣差,有可能進行一次遍歷,系統需要多次進行頁交換,大大降低了效率。
4.避免執行緒同步的開銷
在預設情況下,系統中線程對堆的訪問是依次進行的,如果你自己建立了堆,系統將不會用額外**來保證執行緒的安全性,就會在一定程度上減小系統的消耗,不過這時候對堆的記憶體操作將有我們自己進行,系統將不再管理。
5.快速釋放
如果我們建立乙個堆來存放資料,我們在銷毀資料的時候可以僅僅將整個堆的記憶體釋放,而不必乙個個節點去釋放,大大加快了釋放記憶體的效率。
如何建立額外的堆
我們可以呼叫heapcreate函式來建立額外的堆。函式原型如下:
handlewinapi
heapcreate(
_in_ dword floptions, //表示對堆的操作應該如何進行
_in_ size_t dwinitialsize, //表示一開始系統調撥給堆的位元組數,如果需要系統會將這個值向上取整到cpu頁面的整數倍
_in_ size_t dwmaximumsize //向上取整最大位元組數
);
程序的預設堆與自建堆
最近去了一次面試,面試官問道這個程序的自建堆和預設堆的相關問題,我當時感覺答的並不是很好,這時候我決定好好整理一下相關知識跟大家分享。程序預設堆 windows許多重要的函式都用unicode字元和unicode字串來執行它們所有的操作。如果我們呼叫的是乙個函式的ansi版本,那麼該函式的ansi版...
鏈結 裝載與庫 程序的堆
本次只是簡要的總結堆的基本情況,具體的函式分析和堆演算法分析今後會繼續再學習。程式在任意時刻都可能會發出請求,申請或釋放一段記憶體資源,堆由此而生。堆 heap linux程序堆管理linux下的程序堆管理提供了兩種堆空間分配方式 系統呼叫 void mmap void start,size t l...
c 堆記憶體預設大小 不懂什麼堆與棧,看這裡
堆 heap 與棧 stack 是開發人員必須面對的兩個概念,在理解這兩個概念時,需要放到具體的場景下,因為不同場景下,堆與棧代表不同的含義。一般情況下,有兩層含義 1 程式記憶體布局場景下,堆與棧表示的是兩種記憶體管理方式 2 資料結構場景下,堆與棧表示兩種常用的資料結構 其中函式中定義的區域性變...