1. 程式人生 > >C/C++ —— 程序內存的分區

C/C++ —— 程序內存的分區

虛擬內存 頻繁 http static變量 堆區 print 變量定義的位置 fun ext

本文轉載自:https://blog.csdn.net/shulianghan/article/details/20472269

C語言程序內存分配

(1) 內存分區狀況

棧區 (stack) :

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

-- 存放內容 : 局部變量, 參數;

-- 特點 : 具有 後進先出 特性, 適合用於 保存 回復 現場;

堆區 (heap) :

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

-- 存放內容 : 存放程序運行中 動態分配 內存的數據;

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

堆區內存申請 :

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

-- 剩余內存處理 : 系統會將多余的部分重新放回 空閑內存鏈表中;

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

全局區/靜態區 (數據段 data segment / bss segment) :

-- 分配, 釋放方式 : 編譯器分配內存, 程序退出時系統自動釋放內存;

-- 存放內容 : 全局變量, 靜態變量;

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

常量區 :

-- 分配, 釋放方式 : 退出程序由系統自動釋放;

-- 存放內容 : 常量; (比如char *s = "hello",此處的hello就存儲在常量區)


代碼區 (text segment) :

-- 分配, 釋放方式 : 編譯器分配內存, 程序退出時系統自動釋放內存;

-- 存放內容 : 存放函數體的二進制代碼。

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

(2) 內存分配方式

全局內存分配 :

-- 生命周期 : 編譯時分配內存, 程序退出後釋放內存, 與 程序 的生命周期相同;

-- 存儲內容 : 全局變量, 靜態變量;

棧內存分配 :

-- 生命周期 : 函數執行時分配內存, 執行結束後釋放內存;

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

堆內存分配 :

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

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

(3) register變量

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

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

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

(4) extern 變量

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

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

-- 存放位置 : 外部變量 存放在 全局區;

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

extern聲明外部變量的情況 :

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

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

extern編譯原則 :

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

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

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

使用效果 : extern 使用的時候, 可以不帶數據類型;

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

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

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

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

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

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

變量靜態化 :

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

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

關於函數頭文件的引申 :

-- 內部函數 : 單個文件中使用的內部函數, 僅在那個特定文件中定義函數即可;

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

static變量與普通變量區別 :

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

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

static函數與普通函數區別 : static 函數在內存中只保留一份, 普通函數 每調用一次, 就創建一個副本;

.

(6) 堆 和 棧比較

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

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

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

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

-- 申請效率 : stack 由系統分配, 效率高; heap 由程序員分配, 速度慢, 容易產生碎片;

(7) 各區分布情況

由上到下順序 : 棧區(stack) -> 堆區(heap) -> 全局區 -> 字符常量區 -> 代碼區;

技術分享圖片

驗證分區狀況 :

-- 示例程序 :

 1 /*************************************************************************
 2     > File Name: memory.c
 3     > Author: octopus
 4     > Mail: octopus_work.163.com 
 5     > Created Time: Mon 10 Mar 2014 08:34:12 PM CST
 6  ************************************************************************/
 7  
 8 #include<stdio.h>
 9 #include<stdlib.h>
10  
11 int global1 = 0, global2 = 0, global3 = 0;
12  
13 void function(void)
14 {
15         int local4 = 0, local5 = 0, local6 = 0;
16         static int static4 = 0, static5 = 0, static6 = 0;
17         int *p2 = (int*)malloc(sizeof(int));
18  
19         printf("子函數 局部變量 : \n");
20         printf("local4 : %p \n", &local4);
21         printf("local5 : %p \n", &local5);
22         printf("local6 : %p \n", &local6);
23  
24         printf("子函數 指針變量 : \n");
25         printf("p2 : %p \n", p2);
26  
27         printf("全局變量 : \n");
28         printf("global1 : %p \n", &global1);
29         printf("global2 : %p \n", &global2);
30         printf("global3 : %p \n", &global3);
31  
32         printf("子函數 靜態變量 : \n");
33         printf("static4 : %p \n", &static4);
34         printf("static5 : %p \n", &static5);
35         printf("static6 : %p \n", &static6);
36  
37         printf("子函數地址 : \n");
38         printf("function : %p \n", function);
39 }
40  
41 int main(int argc, char **argv)
42 {
43         int local1 = 0, local2 = 0, local3 = 0;
44         static int static1 = 0, static2 = 0, static3 = 0;
45         int *p1 = (int*)malloc(sizeof(int));
46         const int const1 = 0;
47         char *char_p = "char";
48  
49         printf("主函數 局部變量 : \n");
50         printf("local1 : %p \n", &local1);
51         printf("local2 : %p \n", &local2);
52         printf("local3 : %p \n", &local3);
53         printf("const1 : %p \n", &const1);
54  
55         printf("主函數 指針變量 : \n");
56         printf("p1 : %p \n", p1);
57  
58         printf("全局變量 : \n");
59         printf("global1 : %p \n", &global1);
60         printf("global2 : %p \n", &global2);
61         printf("global3 : %p \n", &global3);
62  
63         printf("主函數 靜態變量 : \n");
64         printf("static1 : %p \n", &static1);
65         printf("static2 : %p \n", &static2);
66         printf("static3 : %p \n", &static3);
67  
68         printf("字符串常量 : \n");
69         printf("char_p : %p \n", char_p);
70  
71         printf("主函數地址 : \n");
72         printf("main : %p \n", main);
73  
74  
75         printf("= = = = = = = = = = = = = = = \n");
76  
77         function();
78  
79         return 0;
80 }

-- 執行結果 :

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

C/C++ —— 程序內存的分區