C語(yǔ)言程序內(nèi)存分配
(1) 內(nèi)存分區(qū)狀況
本文引用地址:http://cafeforensic.com/article/201611/322296.htm棧區(qū) (stack):
--分配, 釋放方式: 由編譯器自動(dòng)分配 和 釋放;
--存放內(nèi)容: 局部變量, 參數(shù);
--特點(diǎn): 具有 后進(jìn)先出 特性, 適合用于 保存 回復(fù) 現(xiàn)場(chǎng);
堆區(qū) (heap):
--分配, 釋放方式: 由程序員手動(dòng) 分配(malloc) 和 釋放(free), 如果程序員沒(méi)有釋放, 那么程序退出的時(shí)候, 會(huì)自動(dòng)釋放;
--存放內(nèi)容: 存放程序運(yùn)行中 動(dòng)態(tài)分配 內(nèi)存的數(shù)據(jù);
--特點(diǎn): 大小不固定, 可能會(huì)動(dòng)態(tài)的 放大 或 縮小;
堆區(qū)內(nèi)存申請(qǐng):
--申請(qǐng)過(guò)程: OS中有一個(gè)記錄空閑內(nèi)存地址的鏈表, 如果程序員申請(qǐng)內(nèi)存, 就會(huì)找到空間大于申請(qǐng)內(nèi)存大小的節(jié)點(diǎn), 將該節(jié)點(diǎn)從空間內(nèi)存鏈表中刪除, 并分配該節(jié)點(diǎn);
--剩余內(nèi)存處理: 系統(tǒng)會(huì)將多余的部分重新放回 空閑內(nèi)存鏈表中;
--首地址記錄大小: 分配內(nèi)存的首地址存放該堆的大小, 這樣釋放內(nèi)存的時(shí)候才能正確執(zhí)行;
全局區(qū)/靜態(tài)區(qū) (數(shù)據(jù)段 data segment /bss segment):
--分配, 釋放方式: 編譯器分配內(nèi)存, 程序退出時(shí)系統(tǒng)自動(dòng)釋放內(nèi)存;
--存放內(nèi)容: 全局變量, 靜態(tài)變量;
--特點(diǎn): 全局變量 和 靜態(tài)變量存儲(chǔ)在一個(gè)區(qū)域, 初始化的兩種變量 和 未初始化的 存儲(chǔ)在不同區(qū)域, 但是兩個(gè)區(qū)域是相鄰的;
常量區(qū):
--分配, 釋放方式: 退出程序由系統(tǒng)自動(dòng)釋放;
--存放內(nèi)容: 常量;
代碼區(qū) (text segment):
--分配, 釋放方式: 編譯器分配內(nèi)存, 程序退出時(shí)系統(tǒng)自動(dòng)釋放內(nèi)存;
--存放內(nèi)容: 存放 程序的二進(jìn)制代碼, 和一些特殊常量;
內(nèi)存存放順序 (由上到下): 棧區(qū) -> 堆區(qū) -> 全局區(qū) -> 常量區(qū) -> 代碼區(qū);
(2) 內(nèi)存分配方式
全局內(nèi)存分配:
--生命周期: 編譯時(shí)分配內(nèi)存, 程序退出后釋放內(nèi)存, 與 程序 的生命周期相同;
--存儲(chǔ)內(nèi)容: 全局變量, 靜態(tài)變量;
棧內(nèi)存分配:
--生命周期: 函數(shù)執(zhí)行時(shí)分配內(nèi)存, 執(zhí)行結(jié)束后釋放內(nèi)存;
--特點(diǎn): 該分配運(yùn)算由處理器處理, 效率高, 但是棧內(nèi)存控件有限;
堆內(nèi)存分配:
--生命周期: 調(diào)用 malloc()開始分配, 調(diào)用 free()釋放內(nèi)存, 完全由程序員控制;
--謹(jǐn)慎使用: 如果分配了 沒(méi)有釋放, 會(huì)造成內(nèi)存泄露, 如果頻繁 分配 釋放 會(huì)出現(xiàn)內(nèi)存碎片;
(3) register變量
使用場(chǎng)景: 如果 一個(gè)變量使用頻率特別高, 可以將這個(gè)變量放在 CPU 的寄存器中;
--修飾限制: 只有 局部變量 和 參數(shù) 可以被聲明為 register變量, 全局 和 靜態(tài)的不可以;
--數(shù)量限制: CPU 寄存器 很寶貴, 不能定義太多register變量;
(4) extern 變量
extern變量概念: 聲明外部變量, 外部變量就是在函數(shù)的外部定義的變量, 在本函數(shù)中使用;
--作用域: 從外部變量定義的位置開始, 知道本源碼結(jié)束都可以使用, 但是只能在定義extern后面使用, 前面的代碼不能使用;
--存放位置: 外部變量 存放在 全局區(qū);
extern變量作用: 使用extern修飾外部變量, ① 擴(kuò)展外部變量在本文件中的作用域, ② 將外部變量作用域從一個(gè)文件中擴(kuò)展到工程中的其它文件;
extern聲明外部變量的情況:
--單個(gè)文件內(nèi)聲明: 如果不定義在文件開頭, 其作用范圍只能是 定義位置開始, 文件結(jié)束位置結(jié)束;
--多個(gè)文件中聲明: 兩個(gè)文件中用到一個(gè)外部變量, 只能定義一次, 編譯 和 連接的時(shí)候, 如果沒(méi)有這個(gè)外部變量, 系統(tǒng)會(huì)知道這個(gè)外部變量在別處定義, 將另一個(gè)文件中的外部變量擴(kuò)展到本文件中;
extern編譯原則:
--本文件中能找到: 編譯器遇到 extern 的時(shí)候, 現(xiàn)在本文件中找外部變量的定義的位置, 如果找到, 就將作用域擴(kuò)展到 定義的位置 知道文件結(jié)束;
--本文件中找不到: 如果本文件中找不到, 連接其它文件找外部變量定義, 如果找到, 將外部變量作用域擴(kuò)展到本文件中;
--外部文件找不到: 報(bào)錯(cuò);
使用效果: extern 使用的時(shí)候, 可以不帶數(shù)據(jù)類型;
--本文件: int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就擴(kuò)展為從第一行到文件末尾;
--多文件: 在任意文件中定義了 int A = 0; 在本文件中聲明 extern A, 那么從當(dāng)前位置到文件末尾都可以使用該變量;
(5) static變量 與 全局變量區(qū)別
static 變量 與 全局變量 相同點(diǎn): 全局變量是靜態(tài)存儲(chǔ)的, 存儲(chǔ)的方式 和 位置基本相同;
static 變量 與 全局變量不用點(diǎn): 全局變量的作用域是 整個(gè)項(xiàng)目工程 橫跨過(guò)個(gè)文件, 靜態(tài)變量的作用域是 當(dāng)前文件, 其它文件中使用是無(wú)效的;
變量存儲(chǔ)位置: 全局變量 和 靜態(tài)變量 存放在 全局區(qū)/靜態(tài)去, 局部變量存放在 棧區(qū)(普通變量) 和 堆區(qū)(指針變量);
變量靜態(tài)化:
--局部變量: 局部變量 加上 static , 相當(dāng)于將局部變量的生命周期擴(kuò)大到了整個(gè)文件, 作用域不改變;
--全局變量: 全局變量 加上 static , 相當(dāng)于將全局變量的作用域縮小到了單個(gè)文件, 生命周期是整個(gè)程序的周期;
關(guān)于函數(shù)頭文件的引申:
--內(nèi)部函數(shù): 單個(gè)文件中使用的內(nèi)部函數(shù), 僅在那個(gè)特定文件中定義函數(shù)即可;
--全局函數(shù): 如果要在整個(gè)工程中使用一個(gè)全局函數(shù), 需要將這個(gè)函數(shù)定義在一個(gè)頭文件中;
static變量與普通變量區(qū)別:
--static全局變量 與 全局變量區(qū)別: static 全局變量 只初始化一次, 防止在其它文件中使用;
--static局部變量 與 局部變量區(qū)別: static 局部變量 只初始化一次, 下一次依據(jù)上一次結(jié)果;
static函數(shù)與普通函數(shù)區(qū)別: static 函數(shù)在內(nèi)存中只保留一份, 普通函數(shù) 每調(diào)用一次, 就創(chuàng)建一個(gè)副本;
.
(6) 堆 和 棧比較
堆(heap)和棧(stack)區(qū)別:
--申請(qǐng)方式: stack 由系統(tǒng)自動(dòng)分配, heap 由程序員進(jìn)行分配;
--申請(qǐng)響應(yīng): 如果 stack 沒(méi)有足夠的剩余空間, 就會(huì)溢出; 堆內(nèi)存從鏈表中找空閑內(nèi)存;
--內(nèi)存限制: stack 內(nèi)存是連續(xù)的, 從高位向低位擴(kuò)展, 而且很小, 只有幾M, 是事先定好的, 在文件中配置; heap 是不連續(xù)的, 從低位向高位擴(kuò)展, 系統(tǒng)是由鏈表控制空閑程序, 鏈表從低地址到高地址, 堆大小受虛擬內(nèi)存限制, 一般32位機(jī)器有4G heap;
--申請(qǐng)效率: stack 由系統(tǒng)分配, 效率高; heap 由程序員分配, 速度慢, 容易產(chǎn)生碎片;
(7) 各區(qū)分布情況
.
按照下圖分布: 由上到下順序 : 棧區(qū)(stack) -> 堆區(qū)(heap) -> 全局區(qū) -> 字符常量區(qū) -> 代碼區(qū);
驗(yàn)證分區(qū)狀況:
--示例程序:
- /*************************************************************************
- >FileName:memory.c
- >Author:octopus
- >Mail:octopus_work.163.com
- >CreatedTime:Mon10Mar201408:34:12PMCST
- ************************************************************************/
- #include
- #include
- intglobal1=0,global2=0,global3=0;
- voidfunction(void)
- {
- intlocal4=0,local5=0,local6=0;
- staticintstatic4=0,static5=0,static6=0;
- int*p2=(int*)malloc(sizeof(int));
- printf("子函數(shù)局部變量:");
- printf("local4:%p",&local4);
- printf("local5:%p",&local5);
- printf("local6:%p",&local6);
- printf("子函數(shù)指針變量:");
- printf("p2:%p",p2);
- printf("全局變量:");
- printf("global1:%p",&global1);
- printf("global2:%p",&global2);
- printf("global3:%p",&global3);
- printf("子函數(shù)靜態(tài)變量:");
- printf("static4:%p",&static4);
- printf("static5:%p",&static5);
- printf("static6:%p",&static6);
- printf("子函數(shù)地址:");
- printf("function:%p",function);
- }
- intmain(intargc,char**argv)
- {
- intlocal1=0,local2=0,local3=0;
- staticintstatic1=0,static2=0,static3=0;
- int*p1=(int*)malloc(sizeof(int));
- constintconst1=0;
- char*char_p="char";
- printf("主函數(shù)局部變量:");
- printf("local1:%p",&local1);
- printf("local2:%p",&local2);
- printf("local3:%p",&local3);
- printf("const1:%p",&const1);
- printf("主函數(shù)指針變量:");
- printf("p1:%p",p1);
- printf("全局變量:");
- printf("global1:%p",&global1);
- printf("global2:%p",&global2);
- printf("global3:%p",&global3);
- printf("主函數(shù)靜態(tài)變量:");
- printf("static1:%p",&static1);
- printf("static2:%p",&static2);
- printf("static3:%p",&static3);
- printf("字符串常量:");
- printf("char_p:%p",char_p);
- printf("主函數(shù)地址:");
- printf("main:%p",main);
- printf("===============");
- function();
- return0;
- }
--執(zhí)行結(jié)果:
- [root@ip28pointer]#gccmemory.c
- [root@ip28pointer]#./a.out
- 主函數(shù)局部變量:
- local1:0x7fff75f5eedc
- local2:0x7fff75f5eed8
- local3:0x7fff75f5eed4
- const1:0x7fff75f5eed0
- 主函數(shù)指針變量:
- p1:0x19bad010
- 全局變量:
- global1:0x600e14
- global2:0x600e18
- global3:0x600e1c
- 主函數(shù)靜態(tài)變量:
- static1:0x600e34
- static2:0x600e30
- static3:0x600e2c
- 字符串常量:
- char_p:0x4009f7
- 主函數(shù)地址:
- main:0x40065f
- ===============
- 子函數(shù)局部變量:
- local4:0x7fff75f5eea4
- local5:0x7fff75f5eea0
- local6:0x7fff75f5ee9c
- 子函數(shù)指針變量:
- p2:0x19bad030
- 全局變量:
- global1:0x600e14
- global2:0x600e18
- global3:0x600e1c
- 子函數(shù)靜態(tài)變量:
- static4:0x600e28
- static5:0x600e24
- static6:0x600e20
- 子函數(shù)地址:
- function:0x400528
3. 指針與地址
評(píng)論