新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > C語言程序內(nèi)存分配

C語言程序內(nèi)存分配

作者: 時間:2016-11-27 來源:網(wǎng)絡 收藏

(1) 內(nèi)存分區(qū)狀況

本文引用地址:http://butianyuan.cn/article/201611/322296.htm

棧區(qū) (stack):

--分配, 釋放方式: 由編譯器自動分配 和 釋放;

--存放內(nèi)容: 局部變量, 參數(shù);

--特點: 具有 后進先出 特性, 適合用于 保存 回復 現(xiàn)場;

堆區(qū) (heap):

--分配, 釋放方式: 由程序員手動 分配(malloc) 和 釋放(free), 如果程序員沒有釋放, 那么程序退出的時候, 會自動釋放;

--存放內(nèi)容: 存放程序運行中 動態(tài)分配 內(nèi)存的數(shù)據(jù);

--特點: 大小不固定, 可能會動態(tài)的 放大 或 縮小;

堆區(qū)內(nèi)存申請:

--申請過程: OS中有一個記錄空閑內(nèi)存地址的鏈表, 如果程序員申請內(nèi)存, 就會找到空間大于申請內(nèi)存大小的節(jié)點, 將該節(jié)點從空間內(nèi)存鏈表中刪除, 并分配該節(jié)點;

--剩余內(nèi)存處理: 系統(tǒng)會將多余的部分重新放回 空閑內(nèi)存鏈表中;

--首地址記錄大小: 分配內(nèi)存的首地址存放該堆的大小, 這樣釋放內(nèi)存的時候才能正確執(zhí)行;

全局區(qū)/靜態(tài)區(qū) (數(shù)據(jù)段 data segment /bss segment):

--分配, 釋放方式: 編譯器分配內(nèi)存, 程序退出時系統(tǒng)自動釋放內(nèi)存;

--存放內(nèi)容: 全局變量, 靜態(tài)變量;

--特點: 全局變量 和 靜態(tài)變量存儲在一個區(qū)域, 初始化的兩種變量 和 未初始化的 存儲在不同區(qū)域, 但是兩個區(qū)域是相鄰的;

常量區(qū):

--分配, 釋放方式: 退出程序由系統(tǒng)自動釋放;

--存放內(nèi)容: 常量;


代碼區(qū) (text segment):

--分配, 釋放方式: 編譯器分配內(nèi)存, 程序退出時系統(tǒng)自動釋放內(nèi)存;

--存放內(nèi)容: 存放 程序的二進制代碼, 和一些特殊常量;

內(nèi)存存放順序 (由上到下): 棧區(qū) -> 堆區(qū) -> 全局區(qū) -> 常量區(qū) -> 代碼區(qū);

(2) 內(nèi)存分配方式

全局內(nèi)存分配:

--生命周期: 編譯時分配內(nèi)存, 程序退出后釋放內(nèi)存, 與 程序 的生命周期相同;

--存儲內(nèi)容: 全局變量, 靜態(tài)變量;

棧內(nèi)存分配:

--生命周期: 函數(shù)執(zhí)行時分配內(nèi)存, 執(zhí)行結束后釋放內(nèi)存;

--特點: 該分配運算由處理器處理, 效率高, 但是棧內(nèi)存控件有限;

堆內(nèi)存分配:

--生命周期: 調(diào)用 malloc()開始分配, 調(diào)用 free()釋放內(nèi)存, 完全由程序員控制;

--謹慎使用: 如果分配了 沒有釋放, 會造成內(nèi)存泄露, 如果頻繁 分配 釋放 會出現(xiàn)內(nèi)存碎片;

(3) register變量

使用場景: 如果 一個變量使用頻率特別高, 可以將這個變量放在 CPU 的寄存器中;

--修飾限制: 只有 局部變量 和 參數(shù) 可以被聲明為 register變量, 全局 和 靜態(tài)的不可以;

--數(shù)量限制: CPU 寄存器 很寶貴, 不能定義太多register變量;

(4) extern 變量

extern變量概念: 聲明外部變量, 外部變量就是在函數(shù)的外部定義的變量, 在本函數(shù)中使用;

--作用域: 從外部變量定義的位置開始, 知道本源碼結束都可以使用, 但是只能在定義extern后面使用, 前面的代碼不能使用;

--存放位置: 外部變量 存放在 全局區(qū);

extern變量作用: 使用extern修飾外部變量, ① 擴展外部變量在本文件中的作用域, ② 將外部變量作用域從一個文件中擴展到工程中的其它文件;

extern聲明外部變量的情況:

--單個文件內(nèi)聲明: 如果不定義在文件開頭, 其作用范圍只能是 定義位置開始, 文件結束位置結束;

--多個文件中聲明: 兩個文件中用到一個外部變量, 只能定義一次, 編譯 和 連接的時候, 如果沒有這個外部變量, 系統(tǒng)會知道這個外部變量在別處定義, 將另一個文件中的外部變量擴展到本文件中;

extern編譯原則:

--本文件中能找到: 編譯器遇到 extern 的時候, 現(xiàn)在本文件中找外部變量的定義的位置, 如果找到, 就將作用域擴展到 定義的位置 知道文件結束;

--本文件中找不到: 如果本文件中找不到, 連接其它文件找外部變量定義, 如果找到, 將外部變量作用域擴展到本文件中;

--外部文件找不到: 報錯;

使用效果: extern 使用的時候, 可以不帶數(shù)據(jù)類型;

--本文件: int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就擴展為從第一行到文件末尾;

--多文件: 在任意文件中定義了 int A = 0; 在本文件中聲明 extern A, 那么從當前位置到文件末尾都可以使用該變量;

(5) static變量 與 全局變量區(qū)別

static 變量 與 全局變量 相同點: 全局變量是靜態(tài)存儲的, 存儲的方式 和 位置基本相同;

static 變量 與 全局變量不用點: 全局變量的作用域是 整個項目工程 橫跨過個文件, 靜態(tài)變量的作用域是 當前文件, 其它文件中使用是無效的;

變量存儲位置: 全局變量 和 靜態(tài)變量 存放在 全局區(qū)/靜態(tài)去, 局部變量存放在 棧區(qū)(普通變量) 和 堆區(qū)(指針變量);

變量靜態(tài)化:

--局部變量: 局部變量 加上 static , 相當于將局部變量的生命周期擴大到了整個文件, 作用域不改變;

--全局變量: 全局變量 加上 static , 相當于將全局變量的作用域縮小到了單個文件, 生命周期是整個程序的周期;

關于函數(shù)頭文件的引申:

--內(nèi)部函數(shù): 單個文件中使用的內(nèi)部函數(shù), 僅在那個特定文件中定義函數(shù)即可;

--全局函數(shù): 如果要在整個工程中使用一個全局函數(shù), 需要將這個函數(shù)定義在一個頭文件中;

static變量與普通變量區(qū)別:

--static全局變量 與 全局變量區(qū)別: static 全局變量 只初始化一次, 防止在其它文件中使用;

--static局部變量 與 局部變量區(qū)別: static 局部變量 只初始化一次, 下一次依據(jù)上一次結果;

static函數(shù)與普通函數(shù)區(qū)別: static 函數(shù)在內(nèi)存中只保留一份, 普通函數(shù) 每調(diào)用一次, 就創(chuàng)建一個副本;

.

(6) 堆 和 棧比較

堆(heap)和棧(stack)區(qū)別:

--申請方式: stack 由系統(tǒng)自動分配, heap 由程序員進行分配;

--申請響應: 如果 stack 沒有足夠的剩余空間, 就會溢出; 堆內(nèi)存從鏈表中找空閑內(nèi)存;

--內(nèi)存限制: stack 內(nèi)存是連續(xù)的, 從高位向低位擴展, 而且很小, 只有幾M, 是事先定好的, 在文件中配置; heap 是不連續(xù)的, 從低位向高位擴展, 系統(tǒng)是由鏈表控制空閑程序, 鏈表從低地址到高地址, 堆大小受虛擬內(nèi)存限制, 一般32位機器有4G heap;

--申請效率: stack 由系統(tǒng)分配, 效率高; heap 由程序員分配, 速度慢, 容易產(chǎn)生碎片;

(7) 各區(qū)分布情況

.

按照下圖分布: 由上到下順序 : 棧區(qū)(stack) -> 堆區(qū)(heap) -> 全局區(qū) -> 字符常量區(qū) -> 代碼區(qū);

驗證分區(qū)狀況:

--示例程序:

[cpp]view plaincopy
  1. /*************************************************************************
  2. >FileName:memory.c
  3. >Author:octopus
  4. >Mail:octopus_work.163.com
  5. >CreatedTime:Mon10Mar201408:34:12PMCST
  6. ************************************************************************/
  7. #include
  8. #include
  9. intglobal1=0,global2=0,global3=0;
  10. voidfunction(void)
  11. {
  12. intlocal4=0,local5=0,local6=0;
  13. staticintstatic4=0,static5=0,static6=0;
  14. int*p2=(int*)malloc(sizeof(int));
  15. printf("子函數(shù)局部變量:");
  16. printf("local4:%p",&local4);
  17. printf("local5:%p",&local5);
  18. printf("local6:%p",&local6);
  19. printf("子函數(shù)指針變量:");
  20. printf("p2:%p",p2);
  21. printf("全局變量:");
  22. printf("global1:%p",&global1);
  23. printf("global2:%p",&global2);
  24. printf("global3:%p",&global3);
  25. printf("子函數(shù)靜態(tài)變量:");
  26. printf("static4:%p",&static4);
  27. printf("static5:%p",&static5);
  28. printf("static6:%p",&static6);
  29. printf("子函數(shù)地址:");
  30. printf("function:%p",function);
  31. }
  32. intmain(intargc,char**argv)
  33. {
  34. intlocal1=0,local2=0,local3=0;
  35. staticintstatic1=0,static2=0,static3=0;
  36. int*p1=(int*)malloc(sizeof(int));
  37. constintconst1=0;
  38. char*char_p="char";
  39. printf("主函數(shù)局部變量:");
  40. printf("local1:%p",&local1);
  41. printf("local2:%p",&local2);
  42. printf("local3:%p",&local3);
  43. printf("const1:%p",&const1);
  44. printf("主函數(shù)指針變量:");
  45. printf("p1:%p",p1);
  46. printf("全局變量:");
  47. printf("global1:%p",&global1);
  48. printf("global2:%p",&global2);
  49. printf("global3:%p",&global3);
  50. printf("主函數(shù)靜態(tài)變量:");
  51. printf("static1:%p",&static1);
  52. printf("static2:%p",&static2);
  53. printf("static3:%p",&static3);
  54. printf("字符串常量:");
  55. printf("char_p:%p",char_p);
  56. printf("主函數(shù)地址:");
  57. printf("main:%p",main);
  58. printf("===============");
  59. function();
  60. return0;
  61. }


--執(zhí)行結果:

[cpp]view plaincopy
  1. [root@ip28pointer]#gccmemory.c
  2. [root@ip28pointer]#./a.out
  3. 主函數(shù)局部變量:
  4. local1:0x7fff75f5eedc
  5. local2:0x7fff75f5eed8
  6. local3:0x7fff75f5eed4
  7. const1:0x7fff75f5eed0
  8. 主函數(shù)指針變量:
  9. p1:0x19bad010
  10. 全局變量:
  11. global1:0x600e14
  12. global2:0x600e18
  13. global3:0x600e1c
  14. 主函數(shù)靜態(tài)變量:
  15. static1:0x600e34
  16. static2:0x600e30
  17. static3:0x600e2c
  18. 字符串常量:
  19. char_p:0x4009f7
  20. 主函數(shù)地址:
  21. main:0x40065f
  22. ===============
  23. 子函數(shù)局部變量:
  24. local4:0x7fff75f5eea4
  25. local5:0x7fff75f5eea0
  26. local6:0x7fff75f5ee9c
  27. 子函數(shù)指針變量:
  28. p2:0x19bad030
  29. 全局變量:
  30. global1:0x600e14
  31. global2:0x600e18
  32. global3:0x600e1c
  33. 子函數(shù)靜態(tài)變量:
  34. static4:0x600e28
  35. static5:0x600e24
  36. static6:0x600e20
  37. 子函數(shù)地址:
  38. function:0x400528

3. 指針與地址


上一頁 1 2 下一頁

評論


技術專區(qū)

關閉