首先答這個(gè)問題需要知道這個(gè)問題的重點(diǎn)引瀑。就是兩個(gè)方面:一個(gè)從數(shù)據(jù)結(jié)構(gòu)方面葡粒,一個(gè)要從操作系統(tǒng)中程序內(nèi)存分配方面。
1.堆和棧之?dāng)?shù)據(jù)結(jié)構(gòu)方向
堆
大家最熟悉數(shù)據(jù)結(jié)構(gòu)中的堆就是堆排序了,想看堆排的同學(xué)可以看下我github上的這個(gè)簡短代碼[https://github.com/TeamWe/FOR-C/blob/master/heap.c] 吁系。對就從這個(gè)角度下手药版。堆分為最大堆和最小堆辑舷。最大堆:跟節(jié)點(diǎn)的值大于孩子節(jié)點(diǎn)的值,左右子樹也都是最大堆槽片。經(jīng)常用來查找最大數(shù)和最小數(shù)何缓,面試中問一些大數(shù)據(jù)查找數(shù)值算法一般回答他就沒錯(cuò)了!
棧
基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)有如下的幾個(gè)特點(diǎn)
1还栓,先入后出碌廓,后入先出。
2剩盒,除頭尾節(jié)點(diǎn)之外谷婆,每個(gè)元素有一個(gè)前驅(qū),一個(gè)后繼。
2.操作系統(tǒng)方面
導(dǎo)言-一個(gè)linux的進(jìn)程分布(可選擇跳過)
從一個(gè)進(jìn)程的地址空間的低地址向高地址增長
1.code段波材,就是存放代碼股淡,可讀可執(zhí)行不可寫,也稱為正文段廷区,代碼段唯灵。2.data段,存放已初始化的全局變量和已初始化的static變量(不管是局部static變量<這里面就包括我上篇問題提到的字符串的存儲>還是全局static變量)
3.bss段,存放全局未初始化變量和未初始化的static變量(也是不區(qū)分局部還是全局static變量)
以上這3部分是確定的隙轻,也就是不同的程序埠帕,以上3部分的大小都各不相同,因程序而異玖绿,若未初始化的全局變量定義的多了敛瓷,那么bss區(qū)就大點(diǎn),反之則小點(diǎn)斑匪。
4.heap,也就是堆呐籽,堆在進(jìn)程空間中是自低地址向高地址增長,你在程序中通過動態(tài)申請得到的內(nèi)存空間(c為malloc\free,c++為new\delete)蚀瘸,就是在堆中動態(tài)分配內(nèi)存的狡蝶。(這個(gè)詳細(xì)分配,看我的malloc的底層實(shí)現(xiàn))
5.stack,棧贮勃,程序中每個(gè)函數(shù)中的局部變量贪惹,都是存放在棧中,棧是自高地址向低地址增長的寂嘉。起初奏瞬,堆和棧之間有很大一段空間,然后隨著泉孩,程序的運(yùn)行硼端,堆不斷向高地址增長,棧不斷向高地址增長棵譬,這樣显蝌,堆跟棧之間的空間總有一個(gè)最大界限,超過這個(gè)最大界限订咸,就會出現(xiàn)堆跟棧重疊曼尊,就會出錯(cuò),所以一般來說脏嚷,Linux下的進(jìn)程都有其最大空間的骆撇。
6.再往上,也就是一個(gè)進(jìn)程地址空間的頂部父叙,存放了命令行參數(shù)和環(huán)境變量神郊。
堆和棧
同:兩者在操作系統(tǒng)中都是為了存儲數(shù)據(jù)而存在的肴裙。
異:1.出現(xiàn)錯(cuò)誤的情況:棧由編譯器自動分配釋放,最大的程序問題會出現(xiàn)棧溢出涌乳。堆由程序員手動管理稍有不當(dāng)就會產(chǎn)生內(nèi)存泄漏還有各種segment fault蜻懦。
2.效率:棧申請速度快,堆要經(jīng)過算法篩選比較慢夕晓。操作系統(tǒng)有一個(gè)記錄當(dāng)前空閑內(nèi)存地址的鏈表宛乃,當(dāng)系統(tǒng)收到程序的申請時(shí),會遍歷該鏈表蒸辆,并且尋找第一個(gè)大于當(dāng)前申請的堆空間(這取決于采取何種算法-首次適應(yīng)算法征炼,循環(huán)首次適應(yīng)算法,最佳適應(yīng)算法躬贡,最壞適應(yīng)算法谆奥,快速適應(yīng)算法),然后重新建立新的空閑鏈表拂玻,將這個(gè)節(jié)點(diǎn)分配酸些。另一個(gè)堆慢的原因就是比如int *p = &a;他是要先在p里面找到這個(gè)指針的地址然后再到這個(gè)地址指向的空間尋找所需的數(shù)據(jù),多了一個(gè)步驟固然變慢了檐蚜。
3.內(nèi)容:棧一般放當(dāng)前所需要的數(shù)據(jù)擂仍,堆中隨時(shí)存儲。