C++內(nèi)存分布及用法
一、內(nèi)存基礎(chǔ)
1、內(nèi)存分布
通過(guò)下面一張圖看看C++的內(nèi)存分布:
棧區(qū):由編譯器自動(dòng)分配與釋放,存放為程序運(yùn)行時(shí)函數(shù)分配的局部變量、函數(shù)參數(shù);棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配內(nèi)存的容量有限;
堆區(qū):由new
、malloc
分配的內(nèi)存塊,釋放由應(yīng)用程序控制,不需要編譯器釋放;如果程序員沒(méi)有對(duì)該內(nèi)存進(jìn)行釋放,程序結(jié)束后系統(tǒng)自動(dòng)回收,堆的地方比棧大很多;
靜態(tài)區(qū):存放的是static
的靜態(tài)變量和一些全局變量,特點(diǎn)是只讀、大小固定;靜態(tài)變量和全局變量的存儲(chǔ)期是一起的,一旦靜態(tài)區(qū)的內(nèi)存被分配,要一直等到程序全部結(jié)束后才釋放;
2、棧區(qū)與堆區(qū)的區(qū)別
1、分配方式不同:棧區(qū)系統(tǒng)分配系統(tǒng)回收;堆區(qū)由程序員手動(dòng)申請(qǐng),需要求程序員自行回收,如果沒(méi)有回收,系統(tǒng)在程序結(jié)束后會(huì)進(jìn)行回收,這種情況會(huì)造成內(nèi)存泄漏;
2、生命周期不同:棧區(qū)生命周期是系統(tǒng)分配到系統(tǒng)回收,也就是在大括號(hào)內(nèi);堆區(qū)是從申請(qǐng)到釋放;
3、效率不同:主要原因是地址空間是否連續(xù),棧區(qū)地址空間是連續(xù)的,效率會(huì)高一些;堆區(qū)地址空間不連續(xù),需要遍歷鏈表才能找到最近的地址,效率會(huì)低一些;
4、內(nèi)存碎片:堆區(qū)容易產(chǎn)生內(nèi)存碎片,棧區(qū)不會(huì);
5、生長(zhǎng)方向不同:棧區(qū)申請(qǐng)空間的地址(表示地址的八個(gè)十六進(jìn)制數(shù))是從大到小的,堆區(qū)申請(qǐng)空間地址是從小到大的。棧區(qū)是先進(jìn)后出的原則,類比棧結(jié)構(gòu)的特點(diǎn);
- 棧區(qū)特點(diǎn):更好的局部性,對(duì)象自動(dòng)銷毀;
- 堆區(qū)特點(diǎn):運(yùn)行期動(dòng)態(tài)擴(kuò)展,需要顯示釋放;
注意點(diǎn):申請(qǐng)的空間是在堆區(qū),變量本身是在棧區(qū)!
二、內(nèi)存分配
1、內(nèi)存分配方式
可操作的內(nèi)存分配:
- 靜態(tài)存儲(chǔ)區(qū)分配:
static
靜態(tài)變量、全局變量; - 棧上分配:局部變量;
- 堆上分配:
new
、malloc
進(jìn)行內(nèi)存分配;
不可操作的內(nèi)存分配:
內(nèi)核區(qū)、代碼區(qū)、局部變量的分配也屬于系統(tǒng)分配;
2、new的用法
C++中通常使用new
、delete
來(lái)構(gòu)造和銷毀對(duì)象;
使用new創(chuàng)建對(duì)象,返回的是對(duì)象的首地址,需要用指針接收:
int *y = new int(2); std::cout << *y << std::endl;
對(duì)象的構(gòu)建和銷毀分為兩步:分配內(nèi)存、所分配內(nèi)存上構(gòu)造對(duì)象(銷毀與之類似);
new的幾種常見(jiàn)形式:
new int(2)
:構(gòu)造單一對(duì)象、new int[5]:構(gòu)造數(shù)組;nothrow new
:標(biāo)準(zhǔn)庫(kù)定義,解決內(nèi)存分配失敗異常的問(wèn)題;placement new
:使用已經(jīng)創(chuàng)建的內(nèi)存,跳過(guò)分配內(nèi)存;new auto
;
3、delete用法
根據(jù)分配的是單一對(duì)象還是數(shù)組,采用相應(yīng)的方式銷毀;
int *y = new int[3]; delete[] y;
不能delete
一個(gè)非new返回的內(nèi)存(也就是棧內(nèi)存);delete nullptr
是可被允許的;
同一塊內(nèi)存不能delete
多次;
4、new與malloc的區(qū)別
new
不需要指定分配多大,malloc
使用的時(shí)候必須指定大??;new
的底層實(shí)現(xiàn)就是malloc
,兩者都必須釋放內(nèi)存,不否則容易造成野指針或內(nèi)存泄漏。需要注意一點(diǎn),釋放內(nèi)存后需設(shè)置相關(guān)指針為空指針;
總結(jié):
- 屬性:
new
為關(guān)鍵字(編譯器),malloc是庫(kù)函數(shù)(需引入頭文件); - 參數(shù):
new
無(wú)需指定大小,malloc需指定大??; - 返回類型:new返回對(duì)象指針,
malloc
返回void*; - 對(duì)于自定義的類:new會(huì)調(diào)用構(gòu)造和析構(gòu)函數(shù),malloc不會(huì)調(diào)用構(gòu)造和析構(gòu)函數(shù);
- 分配失?。?/strong>new會(huì)拋出異常,malloc會(huì)返回空;
5、內(nèi)存泄漏
是指由于疏忽或錯(cuò)誤造成程序未能釋放掉不再使用的內(nèi)存的情況,內(nèi)存泄漏并非指內(nèi)存在物理上的小時(shí),而是應(yīng)用程序分配某段內(nèi)存后,由于設(shè)計(jì)錯(cuò)誤,失去該段內(nèi)存的控制從而造成內(nèi)存浪費(fèi);
可能的原因:
- 1、申請(qǐng)后未釋放(最常見(jiàn))
- 2、
void*
指針的釋放 - 3、
new[]
回收時(shí)沒(méi)有用delete[]
,數(shù)組的回收要注意
三、內(nèi)存拓展
1、內(nèi)存概念
計(jì)算機(jī)重要部件之一,是外存與CPU進(jìn)行溝通的橋梁。計(jì)算機(jī)所有程序都是在內(nèi)存運(yùn)行的,因此內(nèi)存的性能對(duì)計(jì)算機(jī)的影響非常大。內(nèi)存也稱為內(nèi)存儲(chǔ)器和主存儲(chǔ)器,作用是暫時(shí)存放CPU的運(yùn)算數(shù)據(jù),以及與硬盤等外部存儲(chǔ)器交換的數(shù)據(jù);
尋址空間:保存內(nèi)存地址的多少,通常我們說(shuō)的4G內(nèi)存,就表示計(jì)算機(jī)能保存2的32次方個(gè)地址,也就是能找到這些地址上的二進(jìn)制信息;
尋址能力:每個(gè)地址里能存多少個(gè)bit
,現(xiàn)在的計(jì)算機(jī)大多數(shù)是16位機(jī)器了;
2、虛擬內(nèi)存
使得系統(tǒng)運(yùn)行實(shí)際的內(nèi)存空間比想象的大得多,虛擬內(nèi)存是可以遠(yuǎn)大于物理內(nèi)存的,同時(shí)主要為了使程序運(yùn)行的時(shí)候可以不限制于只訪問(wèn)內(nèi)存大小,可以通過(guò)虛擬內(nèi)存地址去訪問(wèn)磁盤空間;
每一個(gè)進(jìn)程虛擬內(nèi)存都是獨(dú)立的,獨(dú)立的享有計(jì)算機(jī)的內(nèi)存。虛擬內(nèi)存地址的大小是與地址總線位數(shù)相關(guān),物理內(nèi)存地址的大小是與物理內(nèi)存條的容量與磁盤容量相關(guān)。
四、思考
1、代碼中的b屬于棧區(qū)還是堆區(qū)?
void fun() { int *b = new int[14]; }
b是在棧區(qū)的變量,由于b是一個(gè)局部變量,隨著函數(shù)域 的結(jié)束被釋放,不需要程序員自行釋放,盡管b使用new進(jìn)行初始化,還是可以認(rèn)為分配在棧區(qū);
總結(jié):
本次系統(tǒng)的從內(nèi)存的基礎(chǔ)概念到內(nèi)存分配進(jìn)行了講解,內(nèi)存是我們開(kāi)發(fā)中最重要的一部分,往往邏輯上的錯(cuò)誤就會(huì)造成內(nèi)存泄漏,導(dǎo)致程序無(wú)法運(yùn)行?;蛘咭恍┓峙鋬?nèi)存的方式不夠細(xì)心,也會(huì)造成冗余內(nèi)存的使用。在目前的很多嵌入式板子上,針對(duì)內(nèi)存的接口是必備的,往往也都是基于malloc
修改;
還有一點(diǎn)需要注意,不管任何機(jī)器上運(yùn)行程序,操作的都是虛擬內(nèi)存,內(nèi)部通過(guò)頁(yè)表定位到對(duì)應(yīng)的物理內(nèi)存。關(guān)于硬件方面的本質(zhì),如果做嵌入式端的話需要深入研究。
到此這篇關(guān)于C++內(nèi)存分布及用法的文章就介紹到這了,更多相關(guān)C++內(nèi)存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言內(nèi)存泄漏常見(jiàn)情況及解決方案詳解
這篇文章主要為大家介紹了C語(yǔ)言內(nèi)存泄漏常見(jiàn)情況及解決方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08C++開(kāi)發(fā)的Redis數(shù)據(jù)導(dǎo)入工具優(yōu)化
這篇文章主要介紹了C++開(kāi)發(fā)的Redis數(shù)據(jù)導(dǎo)入工具優(yōu)化方法的相關(guān)資料,需要的朋友可以參考下2015-07-07C語(yǔ)言pow()函數(shù)實(shí)現(xiàn)求x的y次方的值
這篇文章主要介紹了C語(yǔ)言pow()函數(shù)實(shí)現(xiàn)求x的y次方的值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03C/C++實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的示例詳解
動(dòng)態(tài)數(shù)組相比于靜態(tài)數(shù)組具有更大的靈活性,因?yàn)槠浯笮】梢栽谶\(yùn)行時(shí)根據(jù)程序的需要?jiǎng)討B(tài)地進(jìn)行分配和調(diào)整,本文為大家介紹了C++實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的方法,需要的可以參考下2023-08-08