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

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

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

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

內(nèi)存管理是C++最令人切齒痛恨的問題,也是C++最有爭議的問題,C++高手從中獲得了更好的性能,更大的自由,C++菜鳥的收獲則是一遍一遍的檢查代碼和對C++的痛恨,但內(nèi)存管理在C++中無處不在,內(nèi)存泄漏幾乎在每個(gè)C++程序中都會(huì)發(fā)生,因此要想成為C++高手,內(nèi)存管理一關(guān)是必須要過的,除非放棄C++,轉(zhuǎn)到Java或者.NET,他們的內(nèi)存管理基本是自動(dòng)的,當(dāng)然你也放棄了自由和對內(nèi)存的支配權(quán),還放棄了C++超絕的性能。
  程序員們經(jīng)常編寫內(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就要對應(yīng)一個(gè) delete。如果程序員沒有釋放掉,那么在程序結(jié)束后,操作系統(tǒng)會(huì)自動(dòng)回收。
  • 自由存儲(chǔ)區(qū):就是那些由malloc等分配的內(nèi)存塊,他和堆是十分相似的,不過它是用free來結(jié)束自己的生命的。
  • 全局/靜態(tài)存儲(chǔ)區(qū):全局變量和靜態(tài)變量被分配到同一塊內(nèi)存中,在以前的C語言中,全局變量又分為初始化的和未初始化的,在C++里面沒有這個(gè)區(qū)分了,他們共同占用同一塊內(nèi)存區(qū)。
  • 常量存儲(chǔ)區(qū):這是一塊比較特殊的存儲(chǔ)區(qū),他們里面存放的是常量,不允許修改?!?br />

明確區(qū)分堆與棧

堆與棧的區(qū)分問題,似乎是一個(gè)永恒的話題,由此可見,初學(xué)者對此往往是混淆不清的,所以我決定拿他第一個(gè)開刀。 

首先,我們舉一個(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)榱撕唵尾]有釋放內(nèi)存,那么該怎么去釋放呢?是delete p么?澳,錯(cuò)了,應(yīng)該是delete [ ]p,這是為了告訴編譯器:我刪除的是一個(gè)數(shù)組,編譯器就會(huì)根據(jù)相應(yīng)的Cookie信息去進(jìn)行釋放內(nèi)存的工作。

2. C語言中動(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)存是位于堆中的,并且沒有初始化內(nèi)存的內(nèi)容,因此基本上malloc之后,調(diào)用函數(shù)memset來初始化這部分的內(nèi)存空間.

void* malloc (size_t size);

size_t是unsigned int。

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

realloc

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

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

realloc可以對給定的指針?biāo)傅目臻g進(jìn)行擴(kuò)大或者縮小,無論是擴(kuò)張或是縮小,原有內(nèi)存的中內(nèi)容將保持不變.當(dāng)然,對于縮小,則被縮小的那一部分的內(nèi)容會(huì)丟失.realloc并不保證調(diào)整后的內(nè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é)不夠,問題就出來了,那么就使用堆上第一個(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)存空間中的每一位都初始化為零,也就是說,如果你是為字符類型或整數(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;             //沒有初始值
    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()
{
 // 申請單個(gè)Test類型的空間
 Test* p1 = (Test*)malloc(sizeof(Test));
 free(p1);

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

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

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

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
// 如果申請內(nèi)存失敗了,這里會(huì)拋出bad_alloc 類型異常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}

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

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

5.1、new

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

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

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

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

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

5.2、delete

delete也分為兩種情況:

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

5.3、new 數(shù)組

new[]也分為兩種情況:

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

5.4、delete 數(shù)組

delete[]也分為兩種情況:

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

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

相關(guān)文章

最新評論