欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++內(nèi)存管理詳情

 更新時(shí)間:2021年08月31日 10:42:29   作者:一只小梓陌  
這篇文章主要通過(guò)描述了C/C++內(nèi)存分布、C/C++的一些函數(shù)理方面來(lái)展開(kāi)C/C++內(nèi)存管理的內(nèi)容,需要的朋友請(qǐng)參考下文

C/C++內(nèi)存管理

內(nèi)存管理是C++最令人切齒痛恨的問(wèn)題,也是C++最有爭(zhēng)議的問(wèn)題,C++高手從中獲得了更好的性能,更大的自由,C++菜鳥(niǎo)的收獲則是一遍一遍的檢查代碼和對(duì)C++的痛恨,但內(nèi)存管理在C++中無(wú)處不在,內(nèi)存泄漏幾乎在每個(gè)C++程序中都會(huì)發(fā)生,因此要想成為C++高手,內(nèi)存管理一關(guān)是必須要過(guò)的,除非放棄C++,轉(zhuǎn)到Java或者.NET,他們的內(nèi)存管理基本是自動(dòng)的,當(dāng)然你也放棄了自由和對(duì)內(nèi)存的支配權(quán),還放棄了C++超絕的性能。
  程序員們經(jīng)常編寫(xiě)內(nèi)存管理程序,往往提心吊膽。如果不想觸雷,唯一的解決辦法就是發(fā)現(xiàn)所有潛伏的地雷并且排除它們,躲是躲不了的。

1. C/C++內(nèi)存分布

在C++中,內(nèi)存分成5個(gè)區(qū),他們分別是、自由存儲(chǔ)區(qū)、全局/靜態(tài)存儲(chǔ)區(qū)常量存儲(chǔ)區(qū)?!?strong> 

  • 棧:在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
  • 堆:就是那些由 new分配的內(nèi)存塊,他們的釋放編譯器不去管,由我們的應(yīng)用程序去控制,一般一個(gè)new就要對(duì)應(yīng)一個(gè) delete。如果程序員沒(méi)有釋放掉,那么在程序結(jié)束后,操作系統(tǒng)會(huì)自動(dòng)回收。
  • 自由存儲(chǔ)區(qū):就是那些由malloc等分配的內(nèi)存塊,他和堆是十分相似的,不過(guò)它是用free來(lái)結(jié)束自己的生命的。
  • 全局/靜態(tài)存儲(chǔ)區(qū):全局變量和靜態(tài)變量被分配到同一塊內(nèi)存中,在以前的C語(yǔ)言中,全局變量又分為初始化的和未初始化的,在C++里面沒(méi)有這個(gè)區(qū)分了,他們共同占用同一塊內(nèi)存區(qū)。
  • 常量存儲(chǔ)區(qū):這是一塊比較特殊的存儲(chǔ)區(qū),他們里面存放的是常量,不允許修改?!?br />

明確區(qū)分堆與棧

堆與棧的區(qū)分問(wèn)題,似乎是一個(gè)永恒的話題,由此可見(jiàn),初學(xué)者對(duì)此往往是混淆不清的,所以我決定拿他第一個(gè)開(kāi)刀?!?/p>

首先,我們舉一個(gè)例子

void f() { int* p=new int[5]; }

這條短短的一句話就包含了堆與棧,看到new,我們首先就應(yīng)該想到,我們分配了一塊堆內(nèi)存,那么指針p呢?他分配的是一塊棧內(nèi)存,所以這句話的意思就是:在棧內(nèi)存中存放了一個(gè)指向一塊堆內(nèi)存的指針p。在程序會(huì)先確定在堆中分配內(nèi)存的大小,然后調(diào)用operator new分配內(nèi)存,然后返回這塊內(nèi)存的首地址,放入棧中。
這里,我們?yōu)榱撕?jiǎn)單并沒(méi)有釋放內(nèi)存,那么該怎么去釋放呢?是delete p么?澳,錯(cuò)了,應(yīng)該是delete [ ]p,這是為了告訴編譯器:我刪除的是一個(gè)數(shù)組,編譯器就會(huì)根據(jù)相應(yīng)的Cookie信息去進(jìn)行釋放內(nèi)存的工作。

2. C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理方式

void Test ()
{
 int* p1 = (int*) malloc(sizeof(int));
 free(p1);
 
 // 1.malloc/calloc/realloc的區(qū)別是什么?
 int* p2 = (int*)calloc(4, sizeof (int));
 int* p3 = (int*)realloc(p2, sizeof(int)*10);
 
 // 這里需要free(p2)嗎?
 free(p3 );
}

2.1 malloc/calloc/realloc和free

malloc

malloc分配的內(nèi)存是位于堆中的,并且沒(méi)有初始化內(nèi)存的內(nèi)容,因此基本上malloc之后,調(diào)用函數(shù)memset來(lái)初始化這部分的內(nèi)存空間.

void* malloc (size_t size);

size_t是unsigned int。

malloc:分配一塊size Byte大小的內(nèi)存空間,返回一個(gè)指向該塊內(nèi)存開(kāi)始的指針,指針的類型是void
函數(shù)malloc不能初始化所分配的內(nèi)存空間,而函數(shù)calloc能.如果由malloc()函數(shù)分配的內(nèi)存空間原來(lái)沒(méi)有被使用過(guò),則其中的每一位可能都是0;反之, 如果這部分內(nèi)存曾經(jīng)被分配過(guò),則其中可能遺留有各種各樣的數(shù)據(jù).也就是說(shuō),使用malloc()函數(shù)的程序開(kāi)始時(shí)(內(nèi)存空間還沒(méi)有被重新分配)能正常進(jìn)行,但經(jīng)過(guò)一段時(shí)間(內(nèi)存空間還已經(jīng)被重新分配)可能會(huì)出現(xiàn)問(wèn)題.

realloc

realloc則對(duì)malloc申請(qǐng)的內(nèi)存進(jìn)行大小的調(diào)整.

void* realloc (void* ptr, size_t size);

realloc可以對(duì)給定的指針?biāo)傅目臻g進(jìn)行擴(kuò)大或者縮小,無(wú)論是擴(kuò)張或是縮小,原有內(nèi)存的中內(nèi)容將保持不變.當(dāng)然,對(duì)于縮小,則被縮小的那一部分的內(nèi)容會(huì)丟失.realloc并不保證調(diào)整后的內(nèi)存空間和原來(lái)的內(nèi)存空間保持同一內(nèi)存地址.相反,realloc返回的指針很可能指向一個(gè)新的地址.
realloc是從堆上分配內(nèi)存的.當(dāng)擴(kuò)大一塊內(nèi)存空間時(shí),realloc()試圖直接從堆上現(xiàn)存的數(shù)據(jù)后面的那些字節(jié)中獲得附加的字節(jié),如果能夠滿足,自然天下太平;如果數(shù)據(jù)后面的字節(jié)不夠,問(wèn)題就出來(lái)了,那么就使用堆上第一個(gè)有足夠大小的自由塊,現(xiàn)存的數(shù)據(jù)然后就被拷貝至新的位置,而老塊則放回到堆上.這句話傳遞的一個(gè)重要的信息就是數(shù)據(jù)可能被移動(dòng).

calloc

為一個(gè)大小為num的數(shù)組分配內(nèi)存,每個(gè)元素的大小是size,把每個(gè)元素初始化為0。

 void* calloc(size_t numElements, size_t sizeOfElement); 

函數(shù)calloc() 會(huì)將所分配的內(nèi)存空間中的每一位都初始化為零,也就是說(shuō),如果你是為字符類型或整數(shù)類型的元素分配內(nèi)存,那么這些元素將保證會(huì)被初始化為0;如果你是為指針類型的元素分配內(nèi)存,那么這些元素通常會(huì)被初始化為空指針;如果你為實(shí)型數(shù)據(jù)分配內(nèi)存,則這些元素會(huì)被初始化為浮點(diǎn)型的零.

3. C++內(nèi)存管理方式

3.1 new/delete操作內(nèi)置類型

int *i = new int;             //沒(méi)有初始值
    int *j = new int(100);         //初始值為100
    int *iArr = new int[3];        //分配具有3個(gè)元素的數(shù)組
    delete i;                   //釋放單個(gè)變量所占用的內(nèi)存
    delete j;
    delete []iArr;               //釋放數(shù)組所占用的內(nèi)存

3.2 new和delete操作自定義類型

class Test
{
public:
 Test()
  : _data(0)
 {
  cout << "Test():" << this << endl;
 }
 ~Test()
 {
  cout << "~Test():" << this << endl;
 }

private:
 int _data;
};
void Test2()
{
 // 申請(qǐng)單個(gè)Test類型的空間
 Test* p1 = (Test*)malloc(sizeof(Test));
 free(p1);

 // 申請(qǐng)10個(gè)Test類型的空間
 Test* p2 = (Test*)malloc(sizoef(Test) * 10);
 free(p2);
}
void Test2()
{
 // 申請(qǐng)單個(gè)Test類型的對(duì)象
 Test* p1 = new Test;
 delete p1;

 // 申請(qǐng)10個(gè)Test類型的對(duì)象
 Test* p2 = new Test[10];
 delete[] p2;
}

從上例可看出,new調(diào)用了類Test的構(gòu)造函數(shù),而malloc只是分配了空間,并沒(méi)有調(diào)用構(gòu)造函數(shù),因此會(huì)出現(xiàn)調(diào)用Test2函數(shù)時(shí),輸出的結(jié)果具有隨機(jī)性。如果用free釋放“new創(chuàng)建的動(dòng)態(tài)對(duì)象”,那么該對(duì)象因無(wú)法執(zhí)行析構(gòu)函數(shù)而可能導(dǎo)致程序出錯(cuò)。如果用delete釋放“malloc申請(qǐng)的動(dòng)態(tài)內(nèi)存”,理論上講程序不會(huì)出錯(cuò),但是該程序的可讀性很差。所以new/delete必須配對(duì)使用,malloc/free也一樣。
上例中,Test為類的析構(gòu)函數(shù),對(duì)象離開(kāi)作用域或被delete的時(shí)候會(huì)調(diào)用。指針p指向了一個(gè)堆上創(chuàng)建的Test對(duì)象,若用free來(lái)釋放內(nèi)存,則不會(huì)調(diào)用析構(gòu)函數(shù)

4. operator new與operator delete函數(shù)

newdelete操作符,operator new operator delete是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來(lái)申請(qǐng)空間,delete在底層通過(guò)operator delete全局
函數(shù)來(lái)釋放空間

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申請(qǐng)內(nèi)存失敗了,這里會(huì)拋出bad_alloc 類型異常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}

operator new 是通過(guò)malloc來(lái)申請(qǐng)空間,如果malloc申請(qǐng)空間成功就直接返回,否則返回NULL,如果用戶提供該措施就繼續(xù)申請(qǐng),否則就拋異常。operator delete 是通過(guò)free來(lái)釋放空間的

5. new和delete的實(shí)現(xiàn)原理

5.1、new

new操作針對(duì)數(shù)據(jù)類型的處理,分為兩種情況:

(1) 簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要構(gòu)造函數(shù)的類型)

  • 簡(jiǎn)單類型直接調(diào)用operator new分配內(nèi)存;
  • 可以通過(guò)new_handler來(lái)處理new失敗的情況;
  • new分配失敗的時(shí)候不像malloc那樣返回NULL,它直接拋出異常。要判斷是否分配成功應(yīng)該用異常捕獲的機(jī)制;

(2)復(fù)雜數(shù)據(jù)類型(需要由構(gòu)造函數(shù)初始化對(duì)象) 

new 復(fù)雜數(shù)據(jù)類型的時(shí)候先調(diào)用operator new,然后在分配的內(nèi)存上調(diào)用構(gòu)造函數(shù)。

5.2、delete

delete也分為兩種情況:

  • 簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)delete簡(jiǎn)單數(shù)據(jù)類型默認(rèn)只是調(diào)用free函數(shù)。
  • 復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)delete復(fù)雜數(shù)據(jù)類型先調(diào)用析構(gòu)函數(shù)再調(diào)用operator delete。

5.3、new 數(shù)組

new[]也分為兩種情況:

  •  簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)針對(duì)簡(jiǎn)單類型,new[]計(jì)算好大小后調(diào)用operator new。
  • 復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)針對(duì)復(fù)雜類型,new[]會(huì)額外存儲(chǔ)數(shù)組大小。

5.4、delete 數(shù)組

delete[]也分為兩種情況:

  • 簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)針對(duì)簡(jiǎn)單類型,delete和delete[]等同。
  • 復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)針對(duì)復(fù)雜類型,new[]出來(lái)的內(nèi)存只能由delete[]釋放。

到此這篇關(guān)于C/C++內(nèi)存管理詳情的文章就介紹到這了,更多相關(guān)C/C++內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論