天天看點

C語言:記憶體四區C語言之記憶體四區

文章目錄

  • C語言之記憶體四區
    • 棧區
    • 堆區
    • 全局區(靜态區)
    • 代碼區

C語言之記憶體四區

C語言編譯執行在CPU上的時候,其記憶體占用主要可以分為四個區域:棧區、堆區、全局區、代碼區,這四個區域有着不同的存儲特性和存儲位置,下面一一介紹;

棧區

棧區是RAM裡面的一段,主要用于臨時存放函數的參數值、局部變量值,該記憶體的配置設定過程由編譯器進行配置設定,當我們在main中調用一個函數 fun() 的時候,編譯器會将main函數的運作資料進行壓棧做現場保護,儲存main函數運作時對應的寄存器值以及main函數的傳回位址到堆棧,然後将fun的參數進行壓棧,開始運作函數程式,當fun()函數執行完成之後,編譯器會進行出棧操作,彈出目前函數的參數值(局部變量的生命周期就是從壓棧到出棧的這段時間),當SP指針(棧頂指針)指向傳回位址時,會把參數指派給PC(程式計數器),程式跳轉到原先main中調用的地方,然後SP繼續向下走,彈出main函數的運作狀态到寄存器裡面,之後main函數繼續運作程式,這就是棧區的運作流程,運作流程就如下圖:

C語言:記憶體四區C語言之記憶體四區

由上面的描述我們可以明白棧區有如下特點:

  1. 就是RAM裡面一個存儲空間,其生長方向由高位址向低位址生長(到底後就不能繼續生長,記憶體有限),有一個專門的棧頂指針(SP)指向棧頂
  2. 記憶體配置設定的操作由編譯器來進行,程式自動向作業系統申請配置設定以及回收,速度快且使用友善
  3. 棧區通常用來存儲局部變量和函數參數以及函數調用後傳回的位址

堆區

堆區也是RAM裡面的一段,一般由程式員手動配置設定釋放 (比如使用C語言内的malloc和free動态記憶體配置設定) ,調用函數後會向作業系統申請一塊記憶體,當系統收到程式的申請時,會周遊一個記錄空閑記憶體位址的連結清單,尋找第一個空間大于所申請空間的堆結點,然後将該結點從空閑結點連結清單中删除,并将該結點的空間配置設定給程式,若程式員不釋放,程式結束時可能由作業系統回收,如果因為其他原因沒有及時釋放,程式結束後,沒有指針指向這一塊記憶體,則會導緻記憶體洩漏

記憶體洩漏是指程式中動态配置設定的的堆記憶體,由于某些原因無法釋放或者未釋放,造成的記憶體浪費

堆區的特點:

  1. 由程式員來進行配置設定,靈活性大,但其配置設定的速度較慢,位址不連續,容易碎片化
  2. 位址生長方向由低位址往高位址,申請上限由計算機自身的虛拟記憶體來決定
虛拟記憶體的定義是基于對位址空間的重定義的,即把位址空間定義為

連續的虛拟記憶體位址

,以借此「欺騙」程式,使它們以為自己正在使用一大塊的

連續

位址,對程式來說它是連續的,完整的,實際上虛拟記憶體是映射在多個實體記憶體碎片上,還有部分映射到了外部磁盤存儲器上。虛拟記憶體有以下兩個優點:

1.虛拟記憶體位址空間是連續的,沒有碎片

2.虛拟記憶體的最大空間就是CPU的最大尋址空間,不受記憶體大小的限制,能提供比記憶體更大的位址空間

全局區(靜态區)

全局區用于存放全局變量和靜态變量以及常量,變量中**初始化過的變量 ** 和 未初始化的變量或者初始化為0的變量放在不同區域:

  1. 初始化的全局變量和靜态變量在一塊區域
  2. 未初始化的全局變量和未初始化的靜态變量或者初始化為0的全局\靜态變量在相鄰的另一塊區域
  3. 常量如字元串常量,const聲明後的變量存放在常量區

Tips:兩種變量為什麼要分開放呢?

此處主要涉及到程式三段概念:程式三段分為如下三段:

  1. 代碼段(.text段)
  2. 資料段(.data段)
  3. .bbs段

每一段的功能如下:

代碼段:存放指令代碼(局部變量也放在代碼段),隻讀

資料段:存放初始化值不為0的全局變量或靜态變量,可寫

BSS段:存放初始化為0或未初始化的全局或靜态變量,可寫

可以看到程式三段和記憶體四區有一定的對應關系的,初始時啟動代碼會加載記憶體四區的資料,為了讓啟動代碼更加簡單快速,編譯連結器會直接按照分區讀取資料到對應的程式段,比如直接複制全局區的初始化變量到資料段,或者直接将未初始化段的區域直接清零後讀取到.bbs段,簡化啟動流程

注意:程式三段是CPU級别的概念,記憶體四區是C語言級别的概念

代碼區

代碼區用于存放機器指令,代碼區是可共享的(即另外的執行程式可以調用它),主要為了程式可複用,不用同樣的程式放幾份,代碼區通常是隻讀的,主要防止指令被程式意外修改

繼續閱讀