C 記憶體管理

2022-08-03 11:18:15 字數 2651 閱讀 4596

c++記憶體分配分為堆區,棧區,自由儲存區(**區),全域性區(靜態區),常量區5部分

堆:堆是作業系統中的術語,是作業系統所維護的一塊特殊記憶體,用於程式的記憶體動態分配,c語言使用malloc從堆上分配記憶體,使用free釋放已分配的對應記憶體。

棧:在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限,一般以為mb為單位,一般是1mb。

自由儲存區:自由儲存區是c++基於new操作符的乙個抽象概念,凡是通過new操作符進行記憶體申請,該記憶體即為自由儲存區,一般自由儲存區指向堆區,但可以修改自由儲存區指向。

全域性/靜態儲存區:這塊記憶體是在程式編譯的時候就已經分配好的,在程式整個執行期間都存在。例如全域性變數,靜態變數。

常量儲存區:這是一塊比較特殊的儲存區,他們裡面存放的是常量(const),不允許修改。

特徵

new/delete

malloc/free

操作物件

運算子標準庫函式

分配記憶體的位置

自由儲存區

堆記憶體分配成功的返回值

完整型別指標

void*

記憶體分配失敗的返回值

預設丟擲異常

返回null

分配記憶體的大小

由編譯器根據型別計算得出

必須顯式指定位元組數

處理陣列

有處理陣列的new版本new

需要使用者計算陣列的大小後進行記憶體分配

已分配記憶體的擴充

無法直觀地處理

使用realloc簡單完成

是否相互呼叫

可以,看具體的operator new/delete實現

不可呼叫new

分配記憶體時記憶體不足

客戶能夠指定處理函式或重新制定分配器

無法通過使用者**進行處理

函式過載

允許不允許

建構函式與析構函式

呼叫不呼叫

從技術上來說,堆(heap)是c語言和作業系統的術語。堆是作業系統所維護的一塊特殊記憶體,它提供了動態分配的功能,當執行程式呼叫malloc()時就會從中分配,稍後呼叫free可把記憶體交還。而自由儲存是c++中通過new和delete動態分配和釋放物件的抽象概念,通過new來申請的記憶體區域可稱為自由儲存區。基本上,所有的c++編譯器預設使用堆來實現自由儲存,也即是預設的全域性運算子new和delete也許會按照malloc和free的方式來被實現,這時藉由new運算子分配的物件,說它在堆上也對,說它在自由儲存區上也正確。但程式設計師也可以通過過載操作符,改用其他記憶體來實現自由儲存,例如全域性變數做的物件池,這時自由儲存區就區別於堆了。我們所需要記住的就是:

管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程式設計師控制,容易產生memory leak。

空間大小:一般來講在32位系統下,堆記憶體可以達到4g的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的,預設的棧空間大小是1m(vs2017 專案-屬性-鏈結器-系統可以修改)。

碎片問題:對於堆來講,頻繁的malloc/free勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。棧是先進後出的佇列,以至於永遠都不可能有乙個記憶體塊從棧中間彈出。

分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由alloca函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

分配效率:棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是c/c++函式庫提供的,它的機制是很複雜的,例如為了分配一塊記憶體,庫函式會按照一定的演算法在堆記憶體中搜尋可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於記憶體碎片太多),就有可能呼叫系統功能去增加程式資料段的記憶體空間,這樣就有機會分到足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

總結: 一是在堆裡建立了物件占用了記憶體,但是沒有顯式地釋放物件占用的記憶體;二是在類的建構函式中動態的分配了記憶體,但是在析構函式中沒有釋放記憶體或者沒有正確的釋放記憶體;

a.    在釋放物件陣列時在delete中沒有使用方括號;

b.    物件陣列是指:陣列中存放的是物件,只需要delete p,即可呼叫物件陣列中的每個物件的析構函式釋放空間;

c.     指向物件的指標陣列是指:陣列中存放的是指向物件的指標,不僅要釋放每個物件的空間,還要釋放每個指標的空間,delete p只是釋放了每個指標,但是並沒有釋放物件的空間,正確的做法,是通過乙個迴圈,將每個物件釋放了,然後再把指標釋放了;  

d.    沒有將基類的析構函式定義為虛函式。基類指標指向子類物件時,如果基類的析構函式不是virtual,那麼子類的析構函式將不會被呼叫,子類的資源沒有正確是釋放,因此造成記憶體洩露;

記憶體溢位是指程式在申請記憶體時沒有足夠的記憶體空間供其使用。原因可能如下:

a.    記憶體中載入的資料過於龐大;

b.    **中存在死迴圈;

c.     遞迴呼叫太深,導致堆疊溢位等;

d.    記憶體洩漏最終導致記憶體溢位;

參考鏈結

C 記憶體管理 C 記憶體分類

c 記憶體管理 記憶體分類 moakap 在編寫程式過程中,程式設計師必須清楚程式記憶體的分配機制,合理進行記憶體管理,這樣才能得到高效的程式。同時,如果對c 記憶體分配基本概念不理解,使用不當,一方面浪費了寶貴的記憶體資源,降低了程式執行效率,另一方面還會造成程式中意想不到的錯誤。在 c 程式中,...

C 記憶體管理

在嵌入式系統中使用c 的乙個常見問題是記憶體分配,即對new 和 delete 操作符的失控。具有諷刺意味的是,問題的根源卻是c 對記憶體的管理非常的容易而且安全。具體地說,當乙個物件被消除時,它的析構函式能夠安全的釋放所分配的記憶體。這當然是個好事情,但是這種使用的簡單性使得程式設計師們過度使用n...

c 記憶體管理

這裡對我暫時所了解的記憶體機制做個記錄,以後再補。首先是記憶體分配 記憶體主要分為3個部分 一是從靜態儲存區域分配。編譯時分配好,主要存放全域性變數,static變數,程式結束釋放。二是從堆疊區域分配。函式內區域性變數存放的地方。隨變數生命週期自動釋放。效率較高,但大小有限。三是從記憶體池分配,即從...