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

C/C++中的內(nèi)存管理小結(jié)

 更新時(shí)間:2020年05月12日 09:37:07   作者:又偷吃我氮泵_  
這篇文章主要介紹了C/C++中的內(nèi)存管理小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

我們最初熟知的內(nèi)存開(kāi)辟方式:

  • int val = 20: 在??臻g上開(kāi)辟4個(gè)字節(jié)
  • char array[10]: 在??臻g上開(kāi)辟10個(gè)字節(jié)的連續(xù)空間

上述開(kāi)辟空間的方式有兩個(gè)特點(diǎn):

  • 空間開(kāi)辟大小是固定的。
  • 數(shù)組在申明的時(shí)候,必須指定數(shù)組的長(zhǎng)度,它所需要的內(nèi)存在編譯時(shí)分配。

但是對(duì)于空間的需求,不僅僅是上述的情況,有時(shí)候我們需要的空大小在程序運(yùn)行時(shí)才能知道,那此時(shí)靜態(tài)的開(kāi)辟空間的方式就不能滿足了,我們這時(shí)候只能試試動(dòng)態(tài)內(nèi)存開(kāi)辟。

這篇博客就來(lái)帶大家梳理一下C/C++中的內(nèi)存管理。

一:C/C++內(nèi)存分布

對(duì)內(nèi)存分段是計(jì)算機(jī)的管理機(jī)制

1.棧又叫堆棧,存放非靜態(tài)局部變量、函數(shù)參數(shù)和返回值等等,棧是向下增長(zhǎng)的。,處理器的指令集中、效率高,但是分配內(nèi)存的容量有限。(函數(shù)執(zhí)行結(jié)束后這些存儲(chǔ)單元自動(dòng)釋放)
2.內(nèi)存映射段是高效的IO映射方式,用于裝載一個(gè)共享的動(dòng)態(tài)內(nèi)存庫(kù)。用戶可使用系統(tǒng)接口創(chuàng)建共享共享內(nèi)存,做進(jìn)程間通信。
3.堆用于程序運(yùn)行時(shí)動(dòng)態(tài)內(nèi)存分配,堆是向上增長(zhǎng)的。(一般由人為分配釋放,若沒(méi)有人為釋放則程序結(jié)束時(shí)可能由OS回收。)
4.數(shù)據(jù)段存儲(chǔ)全局?jǐn)?shù)據(jù)、靜態(tài)數(shù)據(jù)。(程序結(jié)束后由系統(tǒng)自動(dòng)釋放)
5.代碼段存儲(chǔ)可執(zhí)行的代碼、只讀常量。

注意:
棧區(qū)向下生長(zhǎng),先開(kāi)辟的空間地址大于后開(kāi)辟的空間地址。(int a = 10,int b = 20,&a>&b)
堆區(qū)向上生長(zhǎng),但是不保證后開(kāi)辟的空間地址大于先開(kāi)辟的空間地址,因?yàn)槎褏^(qū)存在人為的空間釋放。

二:C語(yǔ)言中的內(nèi)存管理方式

C語(yǔ)言提供了動(dòng)態(tài)內(nèi)存函數(shù)來(lái)進(jìn)行內(nèi)存的動(dòng)態(tài)開(kāi)辟工作:malloc、calloc、realloc、free

2.1 malloc

函數(shù)功能

void✳ malloc(size_t size以字節(jié)為單位的空間大?。?/p>

舉個(gè)栗子:int* ptr = (int*) malloc(sizeof(int)*10);

malloc向內(nèi)存申請(qǐng)一塊大小為size的連續(xù)可用空間,并返回指向這塊空間的指針。

函數(shù)特性
1.開(kāi)辟成功,返回一個(gè)指向該空間的指針。
2.開(kāi)辟失敗,返回一個(gè)NULL指針,因此malloc的返回值一定要做檢查。
3.返回值的類型是void✳,malloc函數(shù)并不知道開(kāi)辟空間的數(shù)據(jù)類型,具體在使用的時(shí)候由使用者自己決定。
4.如果參數(shù)size為0,malloc的行為是標(biāo)準(zhǔn)未定義的,取決于編譯器。

2.2 calloc

函數(shù)功能

void✳ calloc(size_t num元素個(gè)數(shù),size_t size以字節(jié)為單位的空間大小)

舉個(gè)栗子:int* ptr = calloc(10,sizeof(int));

calloc向內(nèi)存為num個(gè)大小為size的元素開(kāi)辟一塊連續(xù)空間,并且把空間的每個(gè)字節(jié)都初始化為0。

函數(shù)特性
1.開(kāi)辟成功,返回一個(gè)指向該空間的指針。
2.開(kāi)辟失敗,返回一個(gè)NULL指針,因此calloc的返回值一定要做檢查。
3.返回值的類型是void✳,calloc函數(shù)并不知道開(kāi)辟空間的數(shù)據(jù)類型,具體在使用的時(shí)候由使用者自己決定。
4.calloc會(huì)在返回地址之前把申請(qǐng)的空間每個(gè)字節(jié)都初始化為0(calloc適用于對(duì)申請(qǐng)空間的內(nèi)容要求初始化的情況)

注意:對(duì)申請(qǐng)的空間初始化并不完全是好的事情,當(dāng)我們要申請(qǐng)一個(gè)特別大的空間時(shí),初始化會(huì)浪費(fèi)很多很多的時(shí)間。

2.3 realloc

函數(shù)功能

void✳ realloc(void✳ ptr要調(diào)整的內(nèi)存地址,size_t size調(diào)整之后的空間大小)

舉個(gè)栗子:int* p = NULL; p = realloc(ptr,1000); if(p!=NULL)-> ptr = p;

realloc可以對(duì)動(dòng)態(tài)開(kāi)辟的內(nèi)存空間大小進(jìn)行靈活調(diào)整。

函數(shù)特性

1.返回值為調(diào)整之后內(nèi)存空間的起始位置。
2.realloc在調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會(huì)將原內(nèi)存空間中的數(shù)據(jù)移動(dòng)到新的空間。

realloc在調(diào)整內(nèi)存空間時(shí)存在的兩種情況
情況一:原有空間之后有足夠大的空間

直接在原有內(nèi)存空間之后追加空間,原來(lái)空間的數(shù)據(jù)不發(fā)生變化

情況二:原有空間之后沒(méi)有足夠大的空間

在堆空間上重新找一塊合適大小的連續(xù)空間來(lái)使用,這樣函數(shù)返回的是一個(gè)新的內(nèi)存地址。

常見(jiàn)的動(dòng)態(tài)內(nèi)存錯(cuò)誤

1、對(duì)NULL指針的解引用操作。

2、對(duì)動(dòng)態(tài)開(kāi)辟空間越界訪問(wèn)。

3、對(duì)非動(dòng)態(tài)內(nèi)存使用free釋放。

4、釋放一塊動(dòng)態(tài)開(kāi)辟內(nèi)存的一部分。

5、對(duì)同一塊內(nèi)存多次釋放。

6、動(dòng)態(tài)開(kāi)辟內(nèi)存忘記釋放。

以上的錯(cuò)誤都是十分常見(jiàn)的,因此我們?cè)趯?duì)內(nèi)存進(jìn)行操作的時(shí)候一定要萬(wàn)分小心。

典型內(nèi)存泄漏的例子

int main(){
 int* p = (int*)malloc(sizeof(int));
 p = (int*)malloc(sizeof(int));
 free(p);  
 p = NULL;
}

這個(gè)例子中我們明明進(jìn)行了釋放卻也造成了內(nèi)存泄漏,這是因?yàn)槲覀兩暾?qǐng)了兩次內(nèi)存空間,但是用同一個(gè)指針來(lái)接收,只釋放了一次,因此造成了內(nèi)存的泄漏。

進(jìn)行動(dòng)態(tài)的內(nèi)存分配后一定不能忘記在使用完畢后將內(nèi)存空間釋放,并且將指針賦值為NULL,這一點(diǎn)是十分關(guān)鍵的,否則將造成內(nèi)存泄漏和野指針,對(duì)程序造成很大的影響。

三:C++中的內(nèi)存管理方式

C語(yǔ)言內(nèi)存管理方式在C++中可以繼續(xù)使用,但有些地方就無(wú)能為力而且使用起來(lái)比較麻煩,因此C++又提出了自己的內(nèi)存管理方式:通過(guò)new和delete操作符進(jìn)行動(dòng)態(tài)內(nèi)存管理

在C++中我們使用new進(jìn)行內(nèi)存的申請(qǐng),用delete進(jìn)行內(nèi)存的釋放。

3.1 內(nèi)置類型的內(nèi)存分配與釋放

new和malloc一樣會(huì)在堆上開(kāi)辟空間同時(shí)需要我們手動(dòng)進(jìn)行內(nèi)存的釋放,但是new的寫法更加簡(jiǎn)單易于理解同時(shí)我們還可以對(duì)單個(gè)申請(qǐng)的變量進(jìn)行初始化。

舉個(gè)栗子幫助理解

#include <iostream>
using namespace std;
int main(){
 int* a = new int;//等同于int* a = (int*)malloc(sizeof(int));
 int* b = new int[10];//等同于int* b = (int*)malloc(sizeof(int) * 10);
 int* c = new int(10);//new還可以進(jìn)行內(nèi)置類型的初始化
 cout << *c << endl;
  
 delete a;//等同于free(a);
 delete[] b;//等同于free(b);(對(duì)于多個(gè)變量的空間釋放要用delete[])
 delete c;//等同于free(c);
 
 return 0;              
}

3.2 自定義類型的內(nèi)存分配和釋放

針對(duì)自定義類型的內(nèi)存分配和釋放,new不但可以在分配內(nèi)存的時(shí)候手動(dòng)調(diào)用指定的構(gòu)造函數(shù)還會(huì)在分配多個(gè)對(duì)象的空間時(shí)自動(dòng)調(diào)用默認(rèn)構(gòu)造函數(shù),delete也會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),而malloc和free卻做不到這一點(diǎn)。因此可以理解為malloc和free分配出來(lái)的只不過(guò)是一個(gè)和類一樣大小的空間,并不能稱作是一個(gè)對(duì)象,而new和delete分配出來(lái)的才能被成為對(duì)象。

#include <iostream>                 
#include <stdlib.h> 
using namespace std;              
class Stu{                          
public:        
 Stu(){         
   cout << "default building" << endl;
  }
        
  Stu(int num, string name):_num(num), _name(name){        
   cout << "custom building" << endl;
  }
         
  ~Stu(){                
   cout << "destroying" << endl;
  }
private:
 int _num;
 string _name;    
};
       
int main(){     
 cout << "malloc:" << endl;
 Stu* a = (Stu*)malloc(sizeof(Stu));
 cout << "new:" << endl;
 Stu* b = new Stu(1, "張三");
 cout << "malloc:" << endl;
 Stu* c = (Stu*)malloc(sizeof(Stu) * 5);
 cout << "new:" << endl;
 Stu* d = new Stu[5];
 cout << "free:" << endl;
 free(a);
 cout << "delete:" << endl;
 delete b;
 cout << "free:" << endl;
 free(c);
 cout << "delete:" << endl;
 delete[] d;
}       

運(yùn)行結(jié)果:

 malloc:
 new:
 custom building
 malloc:
 new:
 default building
 default building
 default building
 default building
 default building
 free:
 delete:
 destroying
 free:
 delete:
 destroying
 destroying
 destroying
 destroying
 destroying

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

new和delete在C++中其實(shí)被定義為兩個(gè)運(yùn)算符,我們?cè)谑褂眠@兩個(gè)運(yùn)算符的時(shí)候它會(huì)在底層調(diào)用全局函數(shù)operator new和operator delete。

operator new

operator new在底層實(shí)現(xiàn)的源代碼

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 delete

operator delete在底層實(shí)現(xiàn)的源代碼

void operator delete(void *pUserData){
 _CrtMemBlockHeader * pHead;
 RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
 if (pUserData == NULL)
 return;
 _mlock(_HEAP_LOCK); /* block other threads */
 __TRY
 /* get a pointer to memory block header */
 pHead = pHdr(pUserData);
 /* verify block type */
 _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
 _free_dbg( pUserData, pHead->nBlockUse );
 __FINALLY
 _munlock(_HEAP_LOCK); /* release other threads */
 __END_TRY_FINALLY
 return;
}

從源碼中能看出的是operator new和operator delete在底層也是利用malloc和free分配內(nèi)存的,因此可以說(shuō)new和delete不過(guò)是malloc和free的一層封裝。

針對(duì)內(nèi)置類型

如果申請(qǐng)的是內(nèi)置類型的空間,new和malloc,delete和free基本類似,不同的地方是:new/delete申請(qǐng)和釋放的是單個(gè)元素的空間,new[]和delete[]申請(qǐng)的是連續(xù)空間,而且new在申請(qǐng)空間失敗時(shí)會(huì)拋異常,malloc會(huì)返回NULL。

針對(duì)自定義類型

1.new的原理: 調(diào)用operator new申請(qǐng)空間,調(diào)用構(gòu)造函數(shù)完成初始化。
2.delete的原理: 調(diào)用析構(gòu)函數(shù)完成清理,調(diào)用operator delete釋放空間。

四:經(jīng)典面試題

new | delete和malloc | free的相同點(diǎn)和不同點(diǎn)

相同點(diǎn):
new、delete、malloc、free都是從堆上開(kāi)辟空間,并且需要用戶手動(dòng)釋放。

不同點(diǎn):
1.new和delete是操作符,malloc和free是函數(shù)。

2.malloc申請(qǐng)空間不會(huì)進(jìn)行初始化,new申請(qǐng)空間可以初始化。

3.malloc申請(qǐng)空間失敗返回NULL,new申請(qǐng)空間失敗會(huì)拋出異常。

4.針對(duì)自定義類型,new和delete會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)處理。

五:內(nèi)存泄漏

概念:內(nèi)存泄漏指因?yàn)槭韬龌蝈e(cuò)誤造成程序已經(jīng)不再使用的內(nèi)存沒(méi)有被釋放的情況。

危害:長(zhǎng)期運(yùn)行的程序出現(xiàn)內(nèi)存泄漏,會(huì)浪費(fèi)空間,如操作系統(tǒng)、后臺(tái)服務(wù)等等,出現(xiàn)內(nèi)存泄漏會(huì)
導(dǎo)致響應(yīng)越來(lái)越慢,最終卡死。

舉個(gè)栗子幫助理解:

void MemoryLeaks(){
 // 1.內(nèi)存申請(qǐng)了忘記釋放
 int* p1 = (int*)malloc(sizeof(int));
 int* p2 = new int;
 
 // 2.異常安全問(wèn)題
 int* p3 = new int[10];
 Func(); // 這里Func函數(shù)拋異常導(dǎo)致 delete[] p3未執(zhí)行,p3沒(méi)被釋放.
 delete[] p3;
}

5.1 內(nèi)存泄漏的分類

堆內(nèi)存泄漏

程序執(zhí)行中依據(jù)須要分配通過(guò)malloc / calloc / realloc / new等從堆中分配的一塊內(nèi)存,
用完后必須通過(guò)調(diào)用相應(yīng)的 free或者delete 刪掉。假設(shè)程序的設(shè)計(jì)錯(cuò)誤導(dǎo)致這部分內(nèi)存沒(méi)有被釋放,那么以后這部分空間將無(wú)法再被使用,就會(huì)產(chǎn)生堆內(nèi)存泄漏。

系統(tǒng)資源泄漏

程序使用系統(tǒng)分配的資源,比方套接字、文件描述符、管道等沒(méi)有使用對(duì)應(yīng)的函數(shù)釋放掉,導(dǎo)致系統(tǒng)
資源的浪費(fèi),嚴(yán)重可導(dǎo)致系統(tǒng)效能減少,系統(tǒng)執(zhí)行不穩(wěn)定,產(chǎn)生了系統(tǒng)資源泄露。

5.2 如何檢測(cè)內(nèi)存泄露

在linux下內(nèi)存泄漏檢測(cè)
valgrind、mtrace、dmalloc、memwatch、mpatrol、dbgmem、Electric Fence

在windows下內(nèi)存泄漏檢測(cè)
VLD

5.3 如何避免內(nèi)存泄漏

1.工程前期良好的設(shè)計(jì)規(guī)范,養(yǎng)成良好的編碼規(guī)范,申請(qǐng)的內(nèi)存空間記著匹配的去釋放。

2.采用RAII思想或者智能指針來(lái)管理資源。

5.4 如何在堆上一次申請(qǐng)4G空間

原因:申請(qǐng)失敗一般是因?yàn)檫M(jìn)程地址空間不夠大。

解決辦法:換用64位的進(jìn)程地址空間。

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

相關(guān)文章

  • 嵌入式C實(shí)戰(zhàn)項(xiàng)目開(kāi)發(fā)技巧:對(duì)一個(gè)有規(guī)律的數(shù)組表進(jìn)行位移操作的方法

    嵌入式C實(shí)戰(zhàn)項(xiàng)目開(kāi)發(fā)技巧:對(duì)一個(gè)有規(guī)律的數(shù)組表進(jìn)行位移操作的方法

    今天小編就為大家分享一篇關(guān)于嵌入式C實(shí)戰(zhàn)項(xiàng)目開(kāi)發(fā)技巧:對(duì)一個(gè)有規(guī)律的數(shù)組表進(jìn)行位移操作的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • C++核心編程之占位參數(shù)和默認(rèn)參數(shù)

    C++核心編程之占位參數(shù)和默認(rèn)參數(shù)

    這篇文章主要介紹了C++核心編程之占位參數(shù)和默認(rèn)參數(shù),c++中函數(shù)的形參列表中的形參是可以有默認(rèn)值的,函數(shù)的形參列表里可以有占位參數(shù),用來(lái)占位,調(diào)用函數(shù)時(shí)必須填補(bǔ)位置。下面更多相關(guān)內(nèi)容的詳細(xì)介紹,需要的小伙伴可以參考一下
    2022-03-03
  • OpenGL繪制Bezier曲線的方法

    OpenGL繪制Bezier曲線的方法

    這篇文章主要為大家詳細(xì)介紹了OpenGL繪制Bezier曲線的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C++關(guān)于類結(jié)構(gòu)體大小和構(gòu)造順序,析構(gòu)順序的測(cè)試詳解

    C++關(guān)于類結(jié)構(gòu)體大小和構(gòu)造順序,析構(gòu)順序的測(cè)試詳解

    這篇文章主要介紹了C++類結(jié)構(gòu)體大小和構(gòu)造順序,析構(gòu)順序的測(cè)試,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • openCV4.1.1+VS2019環(huán)境配置詳解

    openCV4.1.1+VS2019環(huán)境配置詳解

    這篇文章主要介紹了openCV4.1.1+VS2019環(huán)境配置詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • QT實(shí)現(xiàn)多線程兩種方式案例詳解

    QT實(shí)現(xiàn)多線程兩種方式案例詳解

    這篇文章主要介紹了QT實(shí)現(xiàn)多線程兩種方式案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • strcat 函數(shù)的使用指南

    strcat 函數(shù)的使用指南

    strcat是連接字符串的函數(shù)。函數(shù)返回指針,兩個(gè)參數(shù)都是指針,第一個(gè)參數(shù)所指向的內(nèi)存的地址必須能容納兩個(gè)字符串連接后的大小。
    2015-09-09
  • C++ 多線程編程建議之 C++ 對(duì)多線程/并發(fā)的支持(下)

    C++ 多線程編程建議之 C++ 對(duì)多線程/并發(fā)的支持(下)

    這篇文章主要介紹的是 C++ 多線程編程建議之 C++ 對(duì)多線程/并發(fā)的支持的相關(guān)資料,承接前文 現(xiàn)代 C++ 對(duì)多線程/并發(fā)的支持,接下來(lái)我們看看回發(fā)生什么吧
    2021-10-10
  • 盤點(diǎn)分析C語(yǔ)言中少見(jiàn)卻強(qiáng)大的字符串函數(shù)

    盤點(diǎn)分析C語(yǔ)言中少見(jiàn)卻強(qiáng)大的字符串函數(shù)

    這篇文章主要為大家盤點(diǎn)及分析C語(yǔ)言中少見(jiàn)卻強(qiáng)大的字符串函數(shù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • c++實(shí)現(xiàn)簡(jiǎn)單的線程池

    c++實(shí)現(xiàn)簡(jiǎn)單的線程池

    本文介紹的線程池采用C++語(yǔ)言,在windows平臺(tái)下實(shí)現(xiàn)。本著技術(shù)分享的精神寫作本文同時(shí)公布源代碼。歡迎大家指出該線程池存在的問(wèn)題并對(duì)當(dāng)前性能進(jìn)行討論。
    2015-03-03

最新評(píng)論