基本概念
棧區(qū)(Stack):由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量等,內(nèi)存的分配是連續(xù)的,類似于數(shù)據(jù)結(jié)構(gòu)中的棧。即,所分配的內(nèi)存是在一塊連續(xù)的內(nèi)存區(qū)域內(nèi).當(dāng)我們聲明變量時(shí),那么編譯器會(huì)自動(dòng)接著當(dāng)前棧區(qū)的結(jié)尾來分配內(nèi)存
堆區(qū)(Heap):一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由操作系統(tǒng)回收.類似于鏈表,在內(nèi)存中的分布不是連續(xù)的,它們是不同區(qū)域的內(nèi)存塊通過指針鏈接起來的.一旦某一節(jié)點(diǎn)從鏈中斷開,我們要人為的把所斷開的節(jié)點(diǎn)從內(nèi)存中釋放
全局/靜態(tài)區(qū)(Static):全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 程序結(jié)束后由系統(tǒng)釋放
文字常量區(qū):常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放
程序代碼區(qū):存放函數(shù)體的二進(jìn)制代碼------------------------------------
靜態(tài)分配:程序編譯鏈接時(shí)分配的大小和使用壽命就已經(jīng)確定
動(dòng)態(tài)分配:在程序執(zhí)行的過程中動(dòng)態(tài)地分配或者回收存儲(chǔ)空間的分配內(nèi)存的方法。動(dòng)態(tài)內(nèi)存分配不像數(shù)組等靜態(tài)內(nèi)存分配方法那樣需要預(yù)先分配存儲(chǔ)空間,而是由系統(tǒng)根據(jù)程序的需要即時(shí)分配,且分配的大小就是程序要求的大小。
內(nèi)存泄露:通常是程序自身編碼缺陷造成。用動(dòng)態(tài)存儲(chǔ)分配函數(shù)動(dòng)態(tài)開辟的空間,在使用完畢后未釋放,結(jié)果導(dǎo)致一直占據(jù)該內(nèi)存單元。直到程序結(jié)束。
內(nèi)存碎片:是一個(gè)系統(tǒng)問題。描述系統(tǒng)中不可以用的空閑內(nèi)存。由于空閑內(nèi)存以小且不連續(xù)方式出現(xiàn)在不同的位置,導(dǎo)致空閑內(nèi)存無法使用,這個(gè)與內(nèi)存管理算法息息相關(guān)。
內(nèi)部碎片:已經(jīng)被分配出去(能明確指出屬于哪個(gè)進(jìn)程)卻不能被利用的內(nèi)存空間;
內(nèi)部碎片產(chǎn)生原因:因?yàn)樗械膬?nèi)存分配必須起始于可被 4、8 或 16 整除(視處理器體系結(jié)構(gòu)而定)的地址或者因?yàn)镸MU的分頁(yè)機(jī)制的限制,決定內(nèi)存分配算法僅能把預(yù)定大小的內(nèi)存塊分配給客戶。假設(shè)當(dāng)某個(gè)客戶請(qǐng)求一個(gè) 43 字節(jié)的內(nèi)存塊時(shí),因?yàn)闆]有適合大小的內(nèi)存,所以它可能會(huì)獲得 44字節(jié)、48字節(jié)等稍大一點(diǎn)的字節(jié),因此由所需大小四舍五入而產(chǎn)生的多余空間就叫內(nèi)部碎片。
外部碎片:指的是還沒有被分配出去(不屬于任何進(jìn)程),但由于太小了無法分配給申請(qǐng)內(nèi)存空間的新進(jìn)程的內(nèi)存空閑區(qū)域。
外部碎片產(chǎn)生原因:頻繁的分配與回收物理頁(yè)面會(huì)導(dǎo)致大量的、連續(xù)且小的頁(yè)面塊夾雜在已分配的頁(yè)面中間,就會(huì)產(chǎn)生外部碎片。如果一個(gè)進(jìn)程申請(qǐng)了一個(gè)8個(gè)單位的內(nèi)存空間,隨后便釋放了。后續(xù)進(jìn)程申請(qǐng)的內(nèi)存空間都大于8(比如是16,32等)。那么這8個(gè)單位的空間永遠(yuǎn)得不到使用,變成外部碎片。
理解到底放哪里
int a = 0; //全局初始化區(qū)
char *p1; //全局未初始化區(qū)
main()
{
int b; //棧
char s[] = "abc"; //棧
char *p2; //棧
char *p3 = "123456"; //123456\0在常量區(qū),p3在棧上。
static int c =0; //全局(靜態(tài))初始化區(qū)
p1 = (char *)malloc(10); //堆
p2 = (char *)malloc(20); //堆
}
堆內(nèi)存與棧內(nèi)存的區(qū)別
申請(qǐng)和回收方式不同:棧上的空間是自動(dòng)分配自動(dòng)回收的,所以棧上的數(shù)據(jù)的生存周期只是在函數(shù)的運(yùn)行過程中,運(yùn)行后就釋放掉,不可以再訪問。而堆上的數(shù)據(jù)只要程序員不釋放空間,就一直可以訪問到,不過缺點(diǎn)是一旦忘記釋放會(huì)造成內(nèi)存泄露。
碎片問題:對(duì)于棧,不會(huì)產(chǎn)生不連續(xù)的內(nèi)存塊;但是對(duì)于堆來說,不斷的new、delete勢(shì)必會(huì)產(chǎn)生上面所述的內(nèi)部碎片和外部碎片。
申請(qǐng)大小的限制:棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,如果申請(qǐng)的空間超過棧的剩余空間,就會(huì)產(chǎn)生棧溢出;對(duì)于堆,是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。
申請(qǐng)效率的比較:棧由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無法控制的;堆:是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便。
當(dāng)然還有存儲(chǔ)內(nèi)容的不一樣
【文章來源簡(jiǎn)書:Martin_wjl 】