堆,棧等概念以及記憶體洩露,記憶體溢位,記憶體越界等問題

2021-09-26 15:54:46 字數 2849 閱讀 5660

在程序中記憶體被分為4個區域,分別是堆,棧,常量區,**區。堆是我們程式設計師能夠直接控制的記憶體區域(既是new malloc),棧是程式自己控制的區域,常量區是存放全域性變數,字串常量的區域以及存放**的**區。

在這之中堆疊是我們要注視的重點。下面我們通過乙個程式了解堆疊的生長方向以及資料的生長方向。

int main(int argc, char* ar**)

; int x = 0;

printf("y = %d \n", y);

printf("y = %p \n", &y);

printf("x = %p \n", &x);

for (int i = 0; i <= 4; ++i)

printf("y = %d\n", y);

//棧 int *p;

p= new int[10];

int *q;

q= new int[10];

for (int j = 0; j < 10; ++j)

for (int k = 0; k < 10; ++k)

delete p;

delete q;

getchar();

return 0;

}

結果是

由上面的**可以看出棧和堆的生長方向是不一樣的,棧是早進棧的分配高位址,晚近棧的分配低位址,堆的符合我們的直覺,先進來的位址比較低。其次,他們的資料生長方向是一樣的,都是低位址到高位址。

堆疊圖:

棧是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放由程式設計師完成,容易產生記憶體洩漏。

一般來講,在32位系統下面,堆記憶體可達到4g的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定空間大小的,例如,在vc6下面,預設的棧大小好像是1m。當然,也可以自己修改:開啟工程。 project-->setting-->link,在category中選中output,然後再reserve中設定堆疊的最大值和 commit。

對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題。

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

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

棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是c/c++庫函式提供的,機制很複雜。庫函式會按照一定的演算法進行分配。顯然,堆的效率比棧要低得多。

注釋:上面是我從網上抄下來的,一般了解就行了不用背,當然,如果要應付面試,覺得有必要的話就要背了,就像tcp與udp的特點  =  -  =。

堆的使用就是  new  型別 ,delete 指標/delete 指標。malloc /calloc(區別是乙個不會初始化為0,一會)。(new和malloc的區別是nwe可以呼叫類的建構函式完成初始化),關於new的用法可以去看 efftive c++。

棧我們是不能直接使用的,任何對棧的呼叫修改都會出現bug。雖然我們不可以手動使用它,但是我們可以簡單的了解他的呼叫模型。

函式呼叫

函式呼叫分為以下幾步:

函式返回

函式返回分為以下幾步:

c++絕大部分的bug都是記憶體使用錯誤,也就是對陣列下標,指標等的使用錯誤。

主要有記憶體溢位,陣列下標越界(記憶體越級),記憶體洩漏等。

細心的人應該發現了,我們在文章開頭所寫的**中,int  y 被由0被改寫成了5。這是因為y是先進棧,然後arr緊接著它進去了,所以他們的位址是相鄰的,在我們for迴圈時,陣列下標越界,給本不應該存在的arr[4]賦值為5,因為他們都是int型別,所以,y的位址就是arr[5]的位址,當給arr[5]賦值時就是給y賦值,所以y的值被改變為了5。這給乙個沒有分配空間的記憶體賦值的操作是違法的,一般稱為記憶體寫越界,相對的還有讀越界,這2個都會破壞棧,造成不可預知的行為,比如上訴的y內改寫為5.。當讀寫的是個非法位址(比如null)時就會造成程式崩潰。現在的編譯器已經很智慧型了,記憶體越界/陣列下標越界都會崩潰報錯提示。上述的**在vs2019就不可以執行,在vc++就可以執行。

記憶體洩漏就是我們new的記憶體delete沒有釋放。你說你不會忘記?呵,當**很簡單時,我們通常都不會忘記,但是百萬航的**呢?儘量減少這種錯誤的方法可以在類內的建構函式nwe,析構函式delete。盡量不要在函式new,在函式外delete,很容易忘記的。還有就是可以使用should_ptr<>這些自能指標,使用計數自動的幫你釋放等。還有要記得new (陣列)要delete 指標 。具體的new優化可以看effective c++的new部分。

記憶體溢位就是分配的記憶體超出了棧的記憶體,不如上面的洩漏,積少成多就會造成溢位。

堆,棧,記憶體洩露,記憶體溢位介紹

簡單的可以理解為 heap 堆 是由malloc之類函式分配的空間所在地。位址是由低向高增長的。stack 棧 是自動分配變數,以及函式呼叫的時候所使用的一些空間。位址是由高向低減少的。一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯...

堆,棧,記憶體洩露,記憶體溢位介紹

簡單的可以理解為 heap 是由malloc之類函式分配的空間所在地。位址是由低向高增長的。stack 是自動分配變數,以及函式呼叫的時候所使用的一些空間。位址是由高向低減少的。一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分...

記憶體洩露和記憶體溢位

一 記憶體洩露 1.定義 指由於疏忽或錯誤造成程式未能釋放已經不再使用的記憶體的情況。記憶體洩漏並非指內存在物理上的消失,而是應用程式分配某段記憶體後,由於設計錯誤,失去了對該段記憶體的控制,因而造成了記憶體的浪費。2.洩露型別 1 堆記憶體洩漏 heap leak a.指利用malloc或new進...