1. 程式人生 > >C++ 記憶體管理

C++ 記憶體管理

記憶體佈局

在C++中記憶體分為5個區,分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。

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

:儲存區域性變數和函式引數等。棧上的內容只在函式的範圍內存在,當函式執行結束,這些內容也會自動被銷燬。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。

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

全域性/靜態儲存區全域性/靜態儲存區:這塊記憶體是在程式編譯的時候就已經分配好的,在程式整個執行期間都存在。例如全域性變數,靜態變數。包括DATA段(全域性初始化區)與BBS段(全域性未初始化段)

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

簡單示例:

#include <iostream>
using namespace std;
int a = 0; //全域性初始化區
char *p1; //全域性未初始化區
int main()
{
       int b; //棧
       char s[] = "abc"; //棧
       char *p2; //棧
       char *p3 = "123456"; //123456在常量區,p3在棧上。
       static int c = 0;     //全域性(靜態)初始化區
p1 = (char *)malloc(10); p2 = (char *)malloc(20);//分配得來得10和20位元組的區域就在堆區。 int *p4 = new int(10); //自由儲存區 strcpy(p1, "123456"); //123456放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。 }

堆和自由儲存區的區別

堆(heap)C語言和作業系統的術語,堆是作業系統所維護的一塊特殊記憶體,它提供了動態分配的功能,當執行程式呼叫malloc()時就會從中分配,呼叫free()歸還記憶體。

自由儲存區(free store)是C++中通過new和delete動態分配和釋放物件的抽象概念,通過new來申請的記憶體區域可稱為自由儲存區,通過delete歸還記憶體。

基本上,所有的C++編譯器預設使用堆來實現自由儲存,運算子new和delete內部預設是使用malloc和free的方式來被實現,預設的全域性運算子new和delete也許會使用malloc和free的方式申請和釋放儲存空間,也就是說自由儲存區就位於堆上。 new和delete是運算子。運算子可以過載,當new被程式設計師過載,且內部實現並非只有malloc()時,此時的記憶體空間就和堆不同了,這是一塊組合的記憶體空間,C++中稱為“自由儲存區”,這是一個抽象的概念。

new和malloc的區別

在這裡插入圖片描述

new、delete原則

1、不要使用delete來釋放不是new分配的記憶體 2、不要使用delete釋放同一個記憶體塊2次 3、如果使用new[]為陣列分配記憶體,則應使用delete[]來釋放 4、如果使用new[]為一個實體分配記憶體,則應使用delete來釋放 5、對空指標使用delete是安全的 6、用 malloc 或 new 申請記憶體之後,應該立即檢查指標值是否為 NULL。防止使用指標值為 NULL 的記憶體。 7、不要忘記為陣列和動態記憶體賦初值。防止將未被初始化的記憶體作為右值使用。 8、避免陣列或指標的下標越界,特別要當心發生“多 1”或者“少 1”操作。 9、動態記憶體的申請與釋放必須配對,防止記憶體洩漏。 10、用 free 或 delete 釋放了記憶體之後,立即將指標設定為 NULL,防止產生“野指標”

堆和棧的區別

定義: 棧區(stack):由編譯器自動分配釋放,存放函式的引數值,區域性變數等值。其操作方式類似於資料結構中的棧。 堆區(heap):一般由程式設計師分配釋放,若程式設計師不釋放,則可能會引起記憶體洩漏。注堆和資料結構中的堆疊不一樣,其類似於連結串列。

堆和棧中的儲存內容: (1)棧:在函式呼叫時,第一個進棧的主函式中後的下一條語句的地址,然後是函式的各個引數,引數是從右往左入棧的,然後是函式中的區域性變數。注:靜態變數是不入棧的。當本次函式呼叫結束後,區域性變數先出棧,然後是引數,最後棧頂指標指向最開始存的地址,也就是主函式中的下一條指令,程式由該點繼續執行。 (2)堆:一般是在堆的頭部用一個位元組存放堆的大小。

區別: 1)空間大小:棧的記憶體空間是連續的,空間大小通常是系統預先規定好的,即棧頂地址和最大空間是確定的;而堆得記憶體空間是不連續的,由一個記錄空間空間的連結串列負責管理,因此記憶體空間幾乎沒有限制,在32位系統下,記憶體空間大小可達到4G 2)管理方式:棧由編譯器自動分配和釋放,而堆需要程式設計師來手動分配和釋放,若忘記delete,容易產生記憶體洩漏。 3)生長方向不同:對於棧,他是向著記憶體地址減小的方向生長的,這也是為什麼棧的記憶體空間是有限的;而堆是向著記憶體地址增大的方向生長的 4)碎片問題:由於棧的記憶體空間是連續的,先進後出的方式保證不會產生零碎的空間;而堆分配方式是每次在空閒連結串列中遍歷到第一個大於申請空間的節點,每次分配的空間大小一般不會正好等於申請的記憶體大小,頻繁的new操作勢必會產生大量的空間碎片 5)分配效率:棧屬於機器系統提供的資料結構,計算機會在底層對棧提供支援,出棧進棧由專門的指令執行,因此效率較高。而堆是c/c++函式庫提供的,當申請空間時需要按照一定的演算法搜尋足夠大小的記憶體空間,當沒有足夠的空間時,還需要額外的處理,因此效率較低。

管理方式 編譯器自動分配管理 程式設計師手動分配釋放,容易引起記憶體洩漏
空間大小 大小固定,超出overflow 計算機系統中有效的虛擬記憶體
管理方式 速度快,效率高 速度慢,效率低,容易產生碎片
管理方式 靜態分配和動態分配 動態分配