天天看點

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。

繼續閱讀