在一個(gè)C語言程序中,能夠獲取的內(nèi)存就是三種情況:棧(stack)、堆(heap)、數(shù)據(jù)區(qū)(.data)
十載專業(yè)的建站公司歷程,堅(jiān)持以創(chuàng)新為先導(dǎo)的網(wǎng)站服務(wù),服務(wù)超過上1000+企業(yè)及個(gè)人,涉及網(wǎng)站設(shè)計(jì)、成都app開發(fā)、微信開發(fā)、平面設(shè)計(jì)、互聯(lián)網(wǎng)整合營銷等多個(gè)領(lǐng)域。在不同行業(yè)和領(lǐng)域給人們的工作和生活帶來美好變化。
棧的詳解
運(yùn)行時(shí)自動(dòng)分配&自動(dòng)回收:棧是自動(dòng)管理的,程序員不需要手工干預(yù)。方便簡單。
反復(fù)使用:棧內(nèi)存在程序中其實(shí)就是那一塊空間,程序反復(fù)使用這一塊空間。
臟內(nèi)存:棧內(nèi)存由于反復(fù)使用,每次使用后程序不會(huì)去清理,因此分配到時(shí)保留原來的值。
臨時(shí)性:(函數(shù)不能返回棧變量的指針,因?yàn)檫@個(gè)空間是臨時(shí)的)
棧會(huì)溢出:因?yàn)椴僮飨到y(tǒng)事先給定了棧的大小,如果在函數(shù)中無窮盡的分配棧內(nèi)存總能用完。
堆內(nèi)存詳解
操作系統(tǒng)堆管理器管理:堆管理器是操作系統(tǒng)的一個(gè)模塊,堆管理內(nèi)存分配靈活,按需分配。
大塊內(nèi)存:堆內(nèi)存管理者總量很大的操作系統(tǒng)內(nèi)存塊,各進(jìn)程可以按需申請使用,使用完釋放。
程序手動(dòng)申請&釋放:手工意思是需要寫代碼去申請malloc和釋放free。
臟內(nèi)存:堆內(nèi)存也是反復(fù)使用的,而且使用者用完釋放前不會(huì)清除,因此也是臟的。
臨時(shí)性:堆內(nèi)存只在malloc和free之間屬于我這個(gè)進(jìn)程,而可以訪問。在malloc之前和free之后都不能再訪問,否則會(huì)有不可預(yù)料的后果。
堆內(nèi)存使用范例
(1)void *是個(gè)指針類型,malloc返回的是一個(gè)void *類型的指針,實(shí)質(zhì)上malloc返回的是堆管理器分配給我本次申請的那段內(nèi)存空間的首地址(malloc返回的值其實(shí)是一個(gè)數(shù)字,這個(gè)數(shù)字表示一個(gè)內(nèi)存地址)。為什么要使用void *作為類型?主要原因是malloc幫我們分配內(nèi)存時(shí)只是分配了內(nèi)存空間,至于這段空間將來用來存儲(chǔ)什么類型的元素malloc是不關(guān)心的,由我們程序自己來決定。
(2)什么是void類型。早期被翻譯成空型,這個(gè)翻譯非常不好,會(huì)誤導(dǎo)人。void類型不表示沒有類型,而表示萬能類型。void的意思就是說這個(gè)數(shù)據(jù)的類型當(dāng)前是不確定的,在需要的時(shí)候可以再去指定它的具體類型。void *類型是一個(gè)指針類型,這個(gè)指針本身占4個(gè)字節(jié),但是指針指向的類型是不確定的,換句話說這個(gè)指針在需要的時(shí)候可以被強(qiáng)制轉(zhuǎn)化成其他任何一種確定類型的指針,也就是說這個(gè)指針可以指向任何類型的元素。
(3)malloc的返回值:成功申請空間后返回這個(gè)內(nèi)存空間的指針,申請失敗時(shí)返回NULL。所以malloc獲取的內(nèi)存指針使用前一定要先檢驗(yàn)是否為NULL。
(4)malloc申請的內(nèi)存時(shí)用完后要free釋放。free(p);會(huì)告訴堆管理器這段內(nèi)存我用完了你可以回收了。堆管理器回收了這段內(nèi)存后這段內(nèi)存當(dāng)前進(jìn)程就不應(yīng)該再使用了。因?yàn)獒尫藕蠖压芾砥骶涂赡馨堰@段內(nèi)存再次分配給別的進(jìn)程,所以你就不能再使用了。
(5)再調(diào)用free歸還這段內(nèi)存之前,指向這段內(nèi)存的指針p一定不能丟(也就是不能給p另外賦值)。因?yàn)閜一旦丟失這段malloc來的內(nèi)存就永遠(yuǎn)的丟失了(內(nèi)存泄漏),直到當(dāng)前程序結(jié)束時(shí)操作系統(tǒng)才會(huì)回收這段內(nèi)存。
malloc的一些細(xì)節(jié)表現(xiàn)
malloc(0)
malloc申請0字節(jié)內(nèi)存本身就是一件無厘頭事情,一般不會(huì)碰到這個(gè)需要。
如果真的malloc(0)返回的是NULL還是一個(gè)有效指針?答案是:實(shí)際分配了16Byte的一段內(nèi)存并且返回了這段內(nèi)存的地址。這個(gè)答案不是確定的,因?yàn)镃語言并沒有明確規(guī)定malloc(0)時(shí)的表現(xiàn),由各malloc函數(shù)庫的實(shí)現(xiàn)者來定義。
malloc(4)
gcc中的malloc默認(rèn)最小是以16B為分配單位的。如果malloc小于16B的大小時(shí)都會(huì)返回一個(gè)16字節(jié)的大小的內(nèi)存。malloc實(shí)現(xiàn)時(shí)沒有實(shí)現(xiàn)任意自己的分配而是允許一些大小的塊內(nèi)存的分配。
代碼段、數(shù)據(jù)段、bss段
(1)編譯器在編譯程序的時(shí)候,將程序中的所有的元素分成了一些組成部分,各部分構(gòu)成一個(gè)段,所以說段是可執(zhí)行程序的組成部分。
(2)代碼段:代碼段就是程序中的可執(zhí)行部分,直觀理解代碼段就是函數(shù)堆疊組成的。
(3)數(shù)據(jù)段(也被稱為數(shù)據(jù)區(qū)、靜態(tài)數(shù)據(jù)區(qū)、靜態(tài)區(qū)):數(shù)據(jù)段就是程序中的數(shù)據(jù),直觀理解就是C語言程序中的全局變量。(注意:全局變量才算是程序的數(shù)據(jù),局部變量不算程序的數(shù)據(jù),只能算是函數(shù)的數(shù)據(jù))
(4)bss段(又叫ZI(zero initial)段):bss段的特點(diǎn)就是被初始化為0,bss段本質(zhì)上也是屬于數(shù)據(jù)段,bss段就是被初始化為0的數(shù)據(jù)段。
注意區(qū)分:數(shù)據(jù)段(.data)和bss段的區(qū)別和聯(lián)系:二者本來沒有本質(zhì)區(qū)別,都是用來存放C程序中的全局變量的。區(qū)別在于把顯示初始化為非零的全局變量存在.data段中,而把顯式初始化為0或者并未顯式初始化(C語言規(guī)定未顯式初始化的全局變量值默認(rèn)為0)的全局變量存在bss段。
有些特殊數(shù)據(jù)會(huì)被放到代碼段
(1)C語言中使用char *p = "linux";定義字符串時(shí),字符串"linux"實(shí)際被分配在代碼段,也就是說這個(gè)"linux"字符串實(shí)際上是一個(gè)常量字符串而不是變量字符串。
(2)const型常量:C語言中const關(guān)鍵字用來定義常量,常量就是不能被改變的量。const的實(shí)現(xiàn)方法至少有2種:第一種就是編譯將const修飾的變量放在代碼段去以實(shí)現(xiàn)不能修改(普遍見于各種單片機(jī)的編譯器);第二種就是由編譯器來檢查以確保const型的常量不會(huì)被修改,實(shí)際上const型的常量還是和普通變量一樣放在數(shù)據(jù)段的(gcc中就是這樣實(shí)現(xiàn)的)。
顯式初始化為非零的全局變量和靜態(tài)局部變量放在數(shù)據(jù)段
(1)放在.data段的變量有2種:第一種是顯式初始化為非零的全局變量。第二種是靜態(tài)局部變量,也就是static修飾的局部變量。(普通局部變量分配在棧上,靜態(tài)局部變量分配在.data段)
未初始化或顯式初始化為0的全局變量放在bss段
(1)bss段和.data段并沒有本質(zhì)區(qū)別,幾乎可以不用明確去區(qū)分這兩種。
C語言中所有變量和常量所使用的內(nèi)存無非以上三種情況。
(1)相同點(diǎn):三種獲取內(nèi)存的方法,都可以給程序提供可用內(nèi)存,都可以用來定義變量給程序用。
(2)不同點(diǎn):棧內(nèi)存對(duì)應(yīng)C中的普通局部變量(別的變量還用不了棧,而且棧是自動(dòng)的,由編譯器和運(yùn)行時(shí)環(huán)境共同來提供服務(wù)的,程序員無法手工控制);堆內(nèi)存完全是獨(dú)立于我們的程序存在和管理的,程序需要內(nèi)存時(shí)可以去手工申請malloc,使用完成后必須盡快free釋放。(堆內(nèi)存對(duì)程序就好象公共圖書館對(duì)于人);數(shù)據(jù)段對(duì)于程序來說對(duì)應(yīng)C程序中的全局變量和靜態(tài)局部變量。
(3)如果我需要一段內(nèi)存來存儲(chǔ)數(shù)據(jù),我究竟應(yīng)該把這個(gè)數(shù)據(jù)存儲(chǔ)在哪里?(或者說我要定義一個(gè)變量,我究竟應(yīng)該定義為局部變量還是全局變量還是用malloc來實(shí)現(xiàn))。不同的存儲(chǔ)方式有不同的特點(diǎn),簡單總結(jié)如下:
* 函數(shù)內(nèi)部臨時(shí)使用,出了函數(shù)不會(huì)用到,就定義局部變量
* 堆內(nèi)存和數(shù)據(jù)段幾乎擁有完全相同的屬性,大部分時(shí)候是可以完全替換的。但是生命周期不一
堆內(nèi)存的生命周期是從malloc開始到free結(jié)束,而全局變量是從整個(gè)程序一開始執(zhí)行就開始,
直到整個(gè)程序結(jié)束才會(huì)消滅,伴隨程序運(yùn)行的一生。啟示:如果你這個(gè)變量只是在程序的一個(gè)
階段有用,用完就不用了,就適合用堆內(nèi)存;如果這個(gè)變量本身和程序是一生相伴的,那就
適合用全局變量。(堆內(nèi)存就好象租房、數(shù)據(jù)段就好象買房。堆內(nèi)存就好象圖書館借書,數(shù)
據(jù)段就好象自己書店買書)你以后會(huì)慢慢發(fā)現(xiàn):買不如租,堆內(nèi)存的使用比全局變量廣泛。
網(wǎng)站標(biāo)題:淺談內(nèi)存分配那些事
文章轉(zhuǎn)載:http://aaarwkj.com/article8/iijoip.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、網(wǎng)站排名、虛擬主機(jī)、網(wǎng)頁設(shè)計(jì)公司、Google、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)