文章目錄
- C語言之記憶體四區
- 堆疊區
- 堆區
- 全域區(靜態區)
- 代碼區
C語言之記憶體四區
C語言編譯執行在CPU上的時候,其記憶體占用主要可以分為四個區域:堆疊區、堆區、全域區、代碼區,這四個區域有著不同的存盤特性和存盤位置,下面一一介紹;
堆疊區
堆疊區是RAM里面的一段,主要用于臨時存放函式的引數值、區域變數值,該記憶體的分配程序由編譯器進行分配,當我們在main中呼叫一個函式 fun() 的時候,編譯器會將main函式的運行資料進行壓堆疊做現場保護,保存main函式運行時對應的暫存器值以及main函式的回傳地址到堆疊,然后將fun的引數進行壓堆疊,開始運行函式程式,當fun()函式執行完成之后,編譯器會進行出堆疊操作,彈出當前函式的引數值(區域變數的生命周期就是從壓堆疊到出堆疊的這段時間),當SP指標(堆疊頂指標)指向回傳地址時,會把引數賦值給PC(程式計數器),程式跳轉到原先main中呼叫的地方,然后SP繼續向下走,彈出main函式的運行狀態到暫存器里面,之后main函式繼續運行程式,這就是堆疊區的運行流程,運行流程就如下圖:

由上面的描述我們可以明白堆疊區有如下特點:
- 就是RAM里面一個存盤空間,其生長方向由高地址向低地址生長(到底后就不能繼續生長,記憶體有限),有一個專門的堆疊頂指標(SP)指向堆疊頂
- 記憶體分配的操作由編譯器來進行,程式自動向作業系統申請分配以及回收,速度快且使用方便
- 堆疊區通常用來存盤區域變數和函式引數以及函式呼叫后回傳的地址
堆區
堆區也是RAM里面的一段,一般由程式員手動分配釋放 (比如使用C語言內的malloc和free動態記憶體分配) ,呼叫函式后會向作業系統申請一塊記憶體,當系統收到程式的申請時,會遍歷一個記錄空閑記憶體地址的鏈表,尋找第一個空間大于所申請空間的堆結點,然后將該結點從空閑結點鏈表中洗掉,并將該結點的空間分配給程式,若程式員不釋放,程式結束時可能由作業系統回收,如果因為其他原因沒有及時釋放,程式結束后,沒有指標指向這一塊記憶體,則會導致記憶體泄漏
記憶體泄漏是指程式中動態分配的的堆記憶體,由于某些原因無法釋放或者未釋放,造成的記憶體浪費
堆區的特點:
- 由程式員來進行分配,靈活性大,但其分配的速度較慢,地址不連續,容易碎片化
- 地址生長方向由低地址往高地址,申請上限由計算機自身的虛擬記憶體來決定
虛擬記憶體的定義是基于對地址空間的重定義的,即把地址空間定義為
連續的虛擬記憶體地址,以借此「欺騙」程式,使它們以為自己正在使用一大塊的連續地址,對程式來說它是連續的,完整的,實際上虛擬記憶體是映射在多個物理記憶體碎片上,還有部分映射到了外部磁盤存盤器上,虛擬記憶體有以下兩個優點:1.虛擬記憶體地址空間是連續的,沒有碎片
2.虛擬記憶體的最大空間就是CPU的最大尋址空間,不受記憶體大小的限制,能提供比記憶體更大的地址空間
全域區(靜態區)
全域區用于存放全域變數和靜態變數以及常量,變數中**初始化過的變數 ** 和 未初始化的變數或者初始化為0的變數放在不同區域:
- 初始化的全域變數和靜態變數在一塊區域
- 未初始化的全域變數和未初始化的靜態變數或者初始化為0的全域\靜態變數在相鄰的另一塊區域
- 常量如字串常量,const宣告后的變數存放在常量區
Tips:兩種變數為什么要分開放呢?
此處主要涉及到程式三段概念:程式三段分為如下三段:
-
代碼段(.text段)
-
資料段(.data段)
-
.bbs段
每一段的功能如下:
代碼段:存放指令代碼(區域變數也放在代碼段),只讀
資料段:存放初始化值不為0的全域變數或靜態變數,可寫
BSS段:存放初始化為0或未初始化的全域或靜態變數,可寫
可以看到程式三段和記憶體四區有一定的對應關系的,初始時啟動代碼會加載記憶體四區的資料,為了讓啟動代碼更加簡單快速,編譯聯結器會直接按照磁區讀取資料到對應的程式段,比如直接復制全域區的初始化變數到資料段,或者直接將未初始化段的區域直接清零后讀取到.bbs段,簡化啟動流程
注意:程式三段是CPU級別的概念,記憶體四區是C語言級別的概念
代碼區
代碼區用于存放機器指令,代碼區是可共享的(即另外的執行程式可以呼叫它),主要為了程式可復用,不用同樣的程式放幾份,代碼區通常是只讀的,主要防止指令被程式意外修改
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/290920.html
標籤:其他
下一篇:C語言實作掃雷簡易版
