天天看點

C++/C的記憶體配置設定

關于C++/C的記憶體配置設定

    • 1、概述
    • 2、記憶體配置設定
      • 2.1、代碼段(text segment)
        • 2.1.1、概述
        • 2.1.2、program
        • 2.1.3、rodata
      • 2.2、BSS段(bss segment)
        • 2.2.1、概述
        • 2.2.1、bss(Block Started by Symbol)
      • 2.3、資料段(data segment)
        • 2.3.1、概述
        • 2.3.2、靜态資料(static data)
        • 2.3.3、堆(heep)
        • 2.3.4、棧(stack)
        • 2.3.4、堆(heep)和棧(stack)的差別
    • 參考文獻

1、概述

在調試C++/C程式時,經常會遇到這樣的現象,程式運作到某個函數時突然奔潰;使用New或者malloc函數配置設定一段記憶體空間時,程式運作一段時間出現奔潰現象。總之,我們經常遇到程式奔潰的問題,而這些問題有時可能也把我們自己搞得很奔潰了。但如果我們能夠了解基本的堆和棧的概念,或許可以避免那些奔潰的瞬間吧。

2、記憶體配置設定

C++/C的記憶體配置設定

常見系統中,都是采用段式記憶體管理架構。這種架構将記憶體空間分為:代碼段(text/code)、資料段(data)和BSS段(bss)。

2.1、代碼段(text segment)

2.1.1、概述

代碼段主要是指存放程式執行代碼的一塊記憶體區域。這部分區域所要占用的大小在程式運作前就已經确定,并且該記憶體區域通常屬于隻讀。在代碼段中,也有可能包含一些隻讀的常量變量。

2.1.2、program

使用者程式存放在代碼段中,并且一般該區域的屬性隻具有隻讀屬性,某些架構下,也允許代碼段為可寫,及允許修改程式。

2.1.3、rodata

該段一般屬于常量區,用于存放常量資料。rodata全稱read only data,及指隻讀資料。是以一般将常量資料存放到該區域,但不是所有的常量都存放在rodata段,有的資料直接放在代碼段中。

  • 常量不一定都放在rodata區域,有的立即數會直接編碼在指令裡,存放在代碼段(.text)中。
  • 對于字元串常量,編譯器會自動去掉重複的字元串,保證一個字元串在一個可執行檔案中隻存在一份拷貝。
  • rodata是在多個程序間是共享的,這可以提高空間使用率
  • 在有的嵌入式系統中,rodata放在ROM裡,運作時直接讀取ROM記憶體,無需要加載到記憶體空間裡

由此可見,在rodata區域的資料,可以在對各程序間共享,可以大大提高空間使用率,甚至可以不占用RAM空間。另外由于rodata是在隻讀的記憶體頁面中,是受保護的,任何修改其值的操作都會被及時發現,這樣可以幫助提高程式的穩定性。

2.2、BSS段(bss segment)

2.2.1、概述

bss段通常用來存放程式中未初始化或初始化為0的全局變量和靜态局部變量。

2.2.1、bss(Block Started by Symbol)

bss段屬于靜态記憶體配置設定,空間結構類似于stack。該區域的資料不會影響最終輸出檔案大小。由于是未初始化的變量,編譯器生成輸出檔案時,就不需要記錄初始值,隻需記錄配置設定的首末位址即可。同樣對于初始值為0的變量,由于初始值已知,是以也不需要在輸出檔案中記錄,隻要在加載時,系統統一指派0即可。

在大多數系統中,注意不是全部,在加載程式時,會把所有的bss段的變量全部清零,無需你手動去清零。但是像我之前接觸過的TI的C2000系列處理器并不會幫你做上述的操作。是以,為了保證程式的可移植性,手動把這些變量初始化為0是比較好的編碼習慣。

2.3、資料段(data segment)

2.3.1、概述

資料段主要用來存儲程式中的初始化的且不為0的全局變量和靜态變量,以及提供可供系統動态配置設定或者使用者程式申請的記憶體空間。

2.3.2、靜态資料(static data)

靜态資料段屬于靜态記憶體配置設定,比較占檔案空間和運作時的記憶體空間。

2.3.3、堆(heep)

堆的記憶體申請和釋放都需要程式去控制,容易産生memory leak,生長方向向上。一般在C++中使用new操作符去申請記憶體空間,使用delete去釋放相應的記憶體。這塊區域的記憶體空間的釋放系統不會去管,需應用程式自己去管理。是以當我們使用new去申請記憶體空間時,一定要注意使用delete去釋放對應的記憶體空間,否則容易導緻記憶體的洩漏。

2.3.4、棧(stack)

棧的記憶體申請和釋放由系統去管理,生長方向向下,及向着記憶體位址減小的方向增長。主要存放函數中的局部變量,以及函數調用時,其參數也會被壓入發起調用的程序棧中,并且待到函數調用結束時,函數的傳回值也會被存放會棧中。由于棧的先進後出的結構特點,是以棧特别友善用來儲存/恢複調用現場。從這個意義上講,我們可以把棧看成一個寄存、交換零時資料的記憶體區。

2.3.4、堆(heep)和棧(stack)的差別

對比
管理方式 使用者管理 系統管理
空間大小 幾乎無限制 有限制
碎片産生
生長方向 向上 向下
配置設定方式 動态 靜态和動态
配置設定效率

參考文獻

1、bss、data和rodata差別與聯系

2、資料段、代碼段、堆棧段、BSS段的差別

3、C/C++記憶體管理詳解

繼續閱讀