C++中內存分配----C++學習之路


1.stack與heap的區別:

stack(棧): 存在於某個作用域的一塊內存空間。也就是說當你調用一個函數,函數本身,也就是在這個函數的scope

中創建一塊地址來存放參數,以及返回地址。離開作用域之後自動清除stack。

heap(堆):由操作系統提供的一塊global內存空間,用動態分配也就是new的方式來動態獲得這塊,但是需要程序員自己

delete它。

stack  object生命期:離開作用域之後就auto地清理掉,自動調用析構函數。

static local object:靜態聲明之後,生命在作用域結束之後仍然存在,直到程序結束後才調用析構函數。

global object:全局對象,也就是說在函數之外,舉個例子就是在int main()這個函數之外聲明。也可以視爲是一個static ob

ject對象。


heap object:舉個例子更容易理解。new生成,delete銷燬。

{
    complex *p = new complex(3);
.
.
.
    delete p;
}這樣事正確的,如果沒有delete的話會造成內存泄漏

內存泄漏:如果發生內存泄露,p這個指針離開作用域後,p已經死亡,但是p指着的那一塊內存仍然存在。


2.new:先分配memory,在動用ctor(構造函數)

看看new在編譯器下會發生怎樣的情況:

Complex* pc=new Complex(1,2);

大部分編譯器中,會先

void* mem = operator new (sizeof(Complex));內部調用malloc(n) c中分配內存

pc = static_cast<Complex*>(mem);  轉型,因爲void於Complex*不符,所以轉型

pc->Complex::Complex(1,2); 調用構造函數。


3.delete:先調用dtor(析構函數),再釋放內存。

delete ps;

在編譯器中:這裏以string對象的例子ps指針

String::~String(ps);字符串本身只是一個指針,字符串的析構函數是刪除ps指向的動態空間

operator delete(ps); 內部調用free(ps),刪除字符串本身。


4.動態分配所得的內存大小。

如果分配一個複數配置。new一個複數,首先是兩個double,8個字節。

在調試模式:在內存頭尾是兩個4字節的cookie,在8字節上有8*4字節的內存,在8字節下有1*4字節的內存。但是每一塊都要是

十六的倍數。這個時候2*4+8*4+2*4+1*4=52=64,在VC下會再填充至64.

不在調試模式:就只有上下cookie,8+*=16=16

上下cookie的作用:指示分配的內存大小,所以malloc函數約定俗成,在上下cookie標識了分配的大小。由最後一位,1或0來定義

給出去還是取回來。

另外:如果是分配一個string中,它實際上只有一個指針的大小,4字節。4+32+4+8=48 所以在cookie中的最後兩位,爲31,表示

48大小,1給出去。48的十六進制是30


5.構造與析構函數。arry new 與arry delete

在字符串中,是m_data = new char[strlen(cstr)+1],所對應的析構函數應該是調用delete[] m_data;而不是delete m_data;

與第四點中的知識配合,如果我們是動態分配一個數組,那麼還會加上一個4字節的內存來表示由多少個元素組成。

也就是說假如Complex* p = new Complex[3];創建一個數組,三個複數,那麼在VC的調試模式下內存大小如下:

8(兩個cookie)+32+4 (這是調試下的debugger Header 與no man land)+8*3 (三個複數元素有六個double)+4(用於表示有幾個元素)

= 72=80   cookie 爲51h。

字符串的情況也一樣,加入String* p = new String[3];就會有三個4字節的指針,加一個4字節的元素數以及cookie與debugger

arrynew要搭配arrydelete。不然會造成內存泄露,這種情況的內存泄露是:拿string舉例子,如果是delete[] p;在第三點中有說過,delete由兩個動作組成

那麼arry delete會調用三次dtor,將這一整塊數組刪除。

但是如果使用delete p;的話,編譯器不會知道你要刪除的是數組,所以它不會調用三次析構函數,鏈接上面的例子,編譯器以爲下面只有一個,

只調用一次析構函數。所以它只回收了第一個指針指向的內存空間,第二個第三個指針指向的內存,就泄露,記住是指向的內存,指針的內存就不會泄露。

如果是複數,因爲複數裏面沒有指針,所以就算複數沒有些arry delete也不會造成危險。

但是養成一個好習慣,就arrynew一定對應arrydelete。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章