在學習c/c++時,我們經常會遇到 堆與堆疊 的問題,今天就來講一下各類情況下的heap,stack的應用,
程式記憶體布局場景下,堆與堆疊表示兩種記憶體管理方式:
1.內部分配時,堆和堆疊表示兩種不同的記憶體管理方式,
2.在討論資料結構時候,堆和堆疊表示兩種不同的資料結構,
1.記憶體分配情況下:
a. 堆:
堆疊由作業系統自動分配釋放 ,用于存放函式的引數值、區域變數等,其操作方式類似于資料結構中的堆疊.
int main()
{
int b; //堆疊
char s[] = "abc"; //堆疊
char *p2; //堆疊
}
其中函式中定義的區域變數按照先后定義的順序依次壓入堆疊中,也就是說相鄰變數的地址之間不會存在其它變數,
堆疊的記憶體地址生長方向與堆相反,由高到底,所以后定義的變數地址低于先定義的變數,比如上面代碼中變數 s 的地址小于變數 b 的地址,p2 地址小于 s 的地址,
堆疊中存盤的資料的生命周期隨著函式的執行完成而結束,
b.堆:
堆由開發人員分配和釋放, 若開發人員不釋放,程式結束時由 OS 回收,分配方式類似于鏈表,堆中存盤的資料若未釋放,則其生命周期等同于程式的生命周期,
堆的記憶體地址生長方向與堆疊相反,由低到高,但是順序不一定固定因為開發者可能釋放掉了之前分配的記憶體,導致后分配的記憶體直接占用了已經被釋放的舊記憶體,
關于堆上記憶體空間的分配程序,首先應該知道作業系統有一個記錄空閑記憶體地址的鏈表,當系統收到程式的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆節點,然后將該節點從空閑節點鏈表中洗掉,并將該節點的空間分配給程式,
另外,對于大多數系統,會在這塊記憶體空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete陳述句才能正確地釋放本記憶體空間,由于找到的堆節點的大小不一定正好等于申請的大小,系統會自動地將多余的那部分重新放入空閑鏈表,
c.總結:
1.堆疊由系統管理,所以不用擔心管理的問題,堆的管理由程式員負責,容易產生記憶體泄漏等隱患,
2.每個行程擁有的堆疊的大小要遠遠小于堆的大小,理論上,程式員可申請的堆大小為虛擬記憶體的大小,行程堆疊的大小 64bits 的 Windows 默認 1MB,64bits 的 Linux 默認 10MB;
3.堆的生長方向向上,記憶體地址由低到高;堆疊的生長方向向下,記憶體地址由高到低,
4.堆只能動態分配,堆疊可以靜態分配和動態,靜態分配是由作業系統完成的,比如區域變數的分配,動態分配由alloca函式進行分配,但是堆疊的動態分配和堆是不同的,它的動態分配是由作業系統進行釋放,
5.分配效率不同,堆疊由作業系統自動分配,會在硬體層級對堆疊提供支持,效率明顯更高,堆則是由C/C++提供的庫函式或運算子來完成申請與管理,實作機制較為復雜,頻繁的記憶體申請容易產生記憶體碎片,顯然,堆的效率比堆疊要低得多,
6.存放內容不同,堆疊存放的內容,函式回傳地址、相關引數、區域變數和暫存器內容等,堆,一般情況堆頂使用一個位元組的空間來存放堆的大小,而堆中具體存放內容是由程式員來填充的,
7.堆疊不是很靈活,所以很多操作仍然要仰仗堆,比如說分配大量的記憶體空間,
2.資料結構情況下:
a.堆疊:
堆疊是一種運算受限的線性表.其限制是指只僅允許在表的一端進行插入和洗掉操作,這種受限的運算使堆疊擁有“先進后出”的特性.
堆疊分順序堆疊和鏈式堆疊兩種,堆疊是一種線性結構,所以可以使用陣列或鏈表(單向鏈表、雙向鏈表或回圈鏈表)作為底層資料結構,
使用陣列實作的堆疊叫做順序堆疊,使用鏈表實作的堆疊叫做鏈式堆疊,二者的區別是順序堆疊中的元素地址連續,鏈式堆疊中的元素地址不連續,
b.堆:
堆是一種常用的樹形結構,是一種特殊的完全二叉樹,當且僅當滿足所有節點的值總是不大于或不小于其父節點的值的完全二叉樹被稱之為堆,
堆的這一特性稱之為堆序性,堆的左右孩子沒有大小的順序,
參考:
https://blog.csdn.net/K346K346/article/details/80849966
https://www.cnblogs.com/mysticCoder/p/4921724.html
https://www.cnblogs.com/jiudianren/p/5671992.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/59737.html
標籤:C
上一篇:C++常用函式
下一篇:函式傳參程序中的資料跑飛(指標)
