C 記憶體管理

2021-10-02 10:31:26 字數 2448 閱讀 1482

記憶體管理是c++最令人頭痛的問題,也是c++最有爭議的地方。c++高手從中獲得了更好的效能,更大的自由,c++菜鳥獲取的則是一遍一遍的檢查**。而這一切都源於c++記憶體管理的靈活性,其多樣的記憶體分配方式就是其靈活性的最好例證之一。

2.堆與棧的區別

3.常見的記憶體處理規則

乙個程式要執行,就必須先將可執行的程式載入到計算機記憶體裡,程式載入完畢後,會形成乙個執行空間,並按照下圖所示進行布局。

這些資料可以動態地反應程式中對函式的呼叫狀態,通過其軌跡也可以研究其函式機制。其中,除了**區不是我們能在**中直接控制的,剩餘三塊都是我們編碼過程中可以利用的。

在c++中,資料區又被分成自由儲存區、全域性/靜態儲存區和常量儲存區,再加上堆區、棧區,也就是說記憶體被分成了5個區。這5種不同的分割槽各有所長,適用於不同的情況。

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

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

自由儲存區是c++基於new操作符的乙個抽象概念,凡是通過new操作符進行記憶體申請,該記憶體即為自由儲存區。

那麼自由儲存區是否能夠是堆(問題等價於new是否能在堆上動態分配記憶體),這取決於operator new 的實現細節。自由儲存區不但可以是堆,還可以是靜態儲存區,這要看operator new在**為物件分配記憶體。具體可以參考c++ 自由儲存區是否等價於堆?這篇文章。

全域性變數和靜態變數被分配到同一塊記憶體中,在以前的c語言中,全域性變數又分為初始化的和未初始化的,在c++裡面沒有作此區分,它們共同占用同一塊記憶體區。

比較特殊,裡面存放的是常量,不允許修改。

上述5種分割槽中,最常用的就是堆和棧了,最容易混淆的也是它們。所以搞清楚堆和棧的區別是很有必要的。它們的區別主要有以下幾個方面

棧是由編譯器自動管理的,無須手工控制;堆的釋放工作由程式設計師控制,容易產生記憶體洩漏。

一般來說在32位系統下,堆記憶體可以達到4gb(2^32b = 4 * 2^30b = 4gb)的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定空間大小的。例如,vs2017預設棧空間大小是1m。

對堆來講,頻繁的new/delete會造成記憶體空間的不連續,從而產生大量的碎片,使程式效率降低。對於棧來講,則不存在這個問題,因為棧是佇列,其中的資料必須遵循先進後出的規則,相互之間緊密排列,絕不會留給其他資料可插入之空隙,所以永遠都不可能有乙個記憶體塊從棧中間彈出。

對於堆來講,其生長方向是向上的,也就是向著記憶體位址增加的方向增長;對於棧來講,它的生長方向是向下的,是向著記憶體位址減小的方向增長的。

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

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

堆和棧相比,由於堆使用了大量new/delete,容易造成大量的記憶體碎片,而且它沒有專門的系統支援,效率很低,另外它還可能引發使用者態和核心態的切換,以及記憶體的申請,代價會變得很高。所以棧在程式中是應用最廣泛的,就算是函式的呼叫也會利用棧去完成,函式呼叫過程中的引數、返回的位址、ebp和區域性變數都是採用棧的方式存放的。所以,推薦大家盡量多用棧,而不是用堆。

雖然棧有如此多的好處,但是由於和堆相比它不是那麼靈活,有時候會分配大量的記憶體空間,在遇到這種情況時還是用堆好一些。

【規則1】用malloc或new申請記憶體之後,應該立即檢查指標值是否為null。防止使用指標值為null的記憶體。

【規則2】不要忘記為陣列和動態記憶體賦初值。防止將未被初始化的記憶體作為右值使用。

【規則3】避免陣列或指標的下標越界,特別要當心發生「多1」或者「少1」操作。

【規則4】動態記憶體的申請與釋放必須配對,防止記憶體洩漏。

【規則5】用free或delete釋放了記憶體之後,立即將指標設定為null,防止產生「野指標」。

個人主頁:

www.codeapes.cn

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

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

C 記憶體管理

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

c 記憶體管理

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