靜態(tài)內(nèi)存區(qū)域解析

通常在代碼中產(chǎn)生的bug,往往是源于概念不清晰。知己知彼百戰(zhàn)不殆,對(duì)內(nèi)存這塊了如指掌,能極大優(yōu)化代碼的性能。

一、內(nèi)存四區(qū)建立流程講解

420E1EED-0A4C-402A-AB84-3ACEFC86E8E3.png

如上圖所示,首先操作系統(tǒng)要把物理硬盤(pán)代碼加載到內(nèi)存中,加載完成后,操作系統(tǒng)會(huì)將代碼分成四個(gè)區(qū)域,即堆區(qū)、棧區(qū)、全局區(qū)和常量區(qū)。最后,操作系統(tǒng)會(huì)找到main函數(shù)入口執(zhí)行程序。這就是內(nèi)存四區(qū)執(zhí)行流程的說(shuō)明。

二、內(nèi)存四區(qū)存儲(chǔ)說(shuō)明
棧區(qū):由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值、局部變量等。
堆區(qū):由程序員動(dòng)態(tài)申請(qǐng)與釋放內(nèi)存,通常用于存放new/malloc關(guān)鍵字創(chuàng)建的值。如果程序員不釋放,程序結(jié)束時(shí)會(huì)由操作系統(tǒng)回收。
全局區(qū):也叫靜態(tài)區(qū),用于存放常量和全局變量,由操作系統(tǒng)管理。全局變量和靜態(tài)變量存儲(chǔ)在一起,初始化的全局變量和靜態(tài)變量在同一塊區(qū)域,未初始化的存儲(chǔ)在相鄰的另一區(qū)域內(nèi)。
程序代碼區(qū):存放函數(shù)體的二進(jìn)制代碼,由操作系統(tǒng)管理。

三、代碼示例

char * getP1(){
    char *p1 = "abcdef";
    return p1;
}
char * getP2(){
    char *p2 = "abcdef2";
    return p2;
}
int main(int argc, const char * argv[]) {
    char *p1 = getP1();
    char *p2 = getP2();
    printf("打印地址:%s,%s\n,",p1,p2);
    printf("打印內(nèi)容:%d,%d\n",p1,p2);
    
    return 0;
}

打印的結(jié)果:

5F6267E1-F728-42C2-93A7-7A1956BA404A.png
char * getP1(){
    char *p1 = "abcdef";
    return p1;
}
char * getP2(){
    char *p2 = "abcdef";
    return p2;
}
int main(int argc, const char * argv[]) {
    char *p1 = getP1();
    char *p2 = getP2();
    printf("打印地址:%s,%s\n,",p1,p2);
    printf("打印內(nèi)容:%d,%d\n",p1,p2);
    
    return 0;
}

打印結(jié)果:

B04FA0BE-D6BF-405C-BEB8-75C32160A58E.png

讓人疑惑的是,為何在不同函數(shù)中聲明的不變量,打印的會(huì)是同樣的內(nèi)容和地址。

C3944F50-ACA9-4347-BEFD-2D92A7A30D43.png

在示例中的代碼中,操作系統(tǒng)進(jìn)入到main函數(shù)的入口,將變量p1,p2放入到棧中。p1和p2分別用來(lái)接收getP1()和getP2()函數(shù)返回的首地址,在64位機(jī)中,只占用內(nèi)存的8個(gè)字節(jié),在getP1()函數(shù)中,也有一個(gè)p1變量,因此把它放入到內(nèi)存的棧中,把常量“abcdef”放入到全局區(qū)中。此時(shí),函數(shù)getP1()中的p1指針是指向“abcdef”,假設(shè)該常量的值是“0xa11”,那就將這個(gè)地址賦給函數(shù)中的p1,函數(shù)的p1要將首地址放回給main函數(shù)中的p1變量。那么main函數(shù)中的p1也會(huì)指向上文中的首地址。這就是p1指針的內(nèi)存解析說(shuō)明。

在編譯程序時(shí),若編譯器檢測(cè)到全局區(qū)有兩個(gè)同樣的值,它就會(huì)代碼進(jìn)行優(yōu)化,在內(nèi)存中只保留一份。當(dāng)這兩個(gè)相同的值放置到全局區(qū)時(shí),他會(huì)統(tǒng)一將這兩個(gè)值合成一個(gè),以避免造成內(nèi)存空間的浪費(fèi)。

所以,當(dāng)編譯器發(fā)現(xiàn)兩個(gè)函數(shù)中變量的值相同之后,就將它們合二為一,p2指針按照上文中p1的分配方式對(duì)內(nèi)存進(jìn)行分配。到最后,就會(huì)發(fā)現(xiàn)p2指針與p1指針指向了相同的地址,且它們的內(nèi)容也是相同的。這就是靜態(tài)內(nèi)存區(qū)域的全部解析。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • C語(yǔ)言中內(nèi)存分配 在任何程序設(shè)計(jì)環(huán)境及語(yǔ)言中,內(nèi)存管理都十分重要。在目前的計(jì)算機(jī)系統(tǒng)或嵌入式系統(tǒng)中,內(nèi)存資源仍然是...
    一生信仰閱讀 1,315評(píng)論 0 2
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛(ài)閱讀 2,255評(píng)論 0 7
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛(ài)DE問(wèn)候閱讀 1,846評(píng)論 0 4
  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,608評(píng)論 0 6
  • 1、注冊(cè)ShareSDK的賬號(hào) 創(chuàng)建應(yīng)用 創(chuàng)建應(yīng)用 獲取應(yīng)用的App Key和App Secret 具體步驟參考官...
    Nicole__Zhang閱讀 2,039評(píng)論 0 1

友情鏈接更多精彩內(nèi)容