一、內存基礎
1、內存分布
通過下面一張圖看看C++的內存分布:
棧區:由編譯器自動分配與釋放,存放為程序運行時函數分配的局部變量、函數參數;棧內存分配運算內置于處理器的指令集中,效率很高,但是分配內存的容量有限;
堆區:由new
、malloc
分配的內存塊,釋放由應用程序控制,不需要編譯器釋放;如果程序員沒有對該內存進行釋放,程序結束后系統自動回收,堆的地方比棧大很多;
靜態區:存放的是static
的靜態變量和一些全局變量,特點是只讀、大小固定;靜態變量和全局變量的存儲期是一起的,一旦靜態區的內存被分配,要一直等到程序全部結束后才釋放;
2、棧區與堆區的區別
1、分配方式不同:棧區系統分配系統回收;堆區由程序員手動申請,需要求程序員自行回收,如果沒有回收,系統在程序結束后會進行回收,這種情況會造成內存泄漏;
2、生命周期不同:棧區生命周期是系統分配到系統回收,也就是在大括號內;堆區是從申請到釋放;
3、效率不同:主要原因是地址空間是否連續,棧區地址空間是連續的,效率會高一些;堆區地址空間不連續,需要遍歷鏈表才能找到最近的地址,效率會低一些;
4、內存碎片:堆區容易產生內存碎片,棧區不會;
5、生長方向不同:棧區申請空間的地址(表示地址的八個十六進制數)是從大到小的,堆區申請空間地址是從小到大的。棧區是先進后出的原則,類比棧結構的特點;
- 棧區特點:更好的局部性,對象自動銷毀;
- 堆區特點:運行期動態擴展,需要顯示釋放;
注意點:申請的空間是在堆區,變量本身是在棧區!
二、內存分配
1、內存分配方式
可操作的內存分配:
-
靜態存儲區分配:
static
靜態變量、全局變量; - 棧上分配:局部變量;
-
堆上分配:
new
、malloc
進行內存分配;
不可操作的內存分配:
內核區、代碼區、局部變量的分配也屬于系統分配;
2、new的用法
C++中通常使用new
、delete
來構造和銷毀對象;
使用new創建對象,返回的是對象的首地址,需要用指針接收:
1
2
|
int *y = new int (2); std::cout << *y << std::endl; |
對象的構建和銷毀分為兩步:分配內存、所分配內存上構造對象(銷毀與之類似);
new的幾種常見形式:
-
new int(2)
:構造單一對象、new int[5]:構造數組; -
nothrow new
:標準庫定義,解決內存分配失敗異常的問題; -
placement new
:使用已經創建的內存,跳過分配內存; -
new auto
;
3、delete用法
根據分配的是單一對象還是數組,采用相應的方式銷毀;
1
2
|
int *y = new int [3]; delete [] y; |
不能delete
一個非new返回的內存(也就是棧內存);
delete nullptr
是可被允許的;
同一塊內存不能delete
多次;
4、new與malloc的區別
new
不需要指定分配多大,malloc
使用的時候必須指定大小;new
的底層實現就是malloc
,兩者都必須釋放內存,不否則容易造成野指針或內存泄漏。需要注意一點,釋放內存后需設置相關指針為空指針;
總結:
-
屬性:
new
為關鍵字(編譯器),malloc是庫函數(需引入頭文件); -
參數:
new
無需指定大小,malloc需指定大小; -
返回類型:new返回對象指針,
malloc
返回void*; - 對于自定義的類:new會調用構造和析構函數,malloc不會調用構造和析構函數;
- 分配失敗:new會拋出異常,malloc會返回空;
5、內存泄漏
是指由于疏忽或錯誤造成程序未能釋放掉不再使用的內存的情況,內存泄漏并非指內存在物理上的小時,而是應用程序分配某段內存后,由于設計錯誤,失去該段內存的控制從而造成內存浪費;
可能的原因:
- 1、申請后未釋放(最常見)
-
2、
void*
指針的釋放 -
3、
new[]
回收時沒有用delete[]
,數組的回收要注意
三、內存拓展
1、內存概念
計算機重要部件之一,是外存與CPU進行溝通的橋梁。計算機所有程序都是在內存運行的,因此內存的性能對計算機的影響非常大。內存也稱為內存儲器和主存儲器,作用是暫時存放CPU的運算數據,以及與硬盤等外部存儲器交換的數據;
尋址空間:保存內存地址的多少,通常我們說的4G內存,就表示計算機能保存2的32次方個地址,也就是能找到這些地址上的二進制信息;
尋址能力:每個地址里能存多少個bit
,現在的計算機大多數是16位機器了;
2、虛擬內存
使得系統運行實際的內存空間比想象的大得多,虛擬內存是可以遠大于物理內存的,同時主要為了使程序運行的時候可以不限制于只訪問內存大小,可以通過虛擬內存地址去訪問磁盤空間;
每一個進程虛擬內存都是獨立的,獨立的享有計算機的內存。虛擬內存地址的大小是與地址總線位數相關,物理內存地址的大小是與物理內存條的容量與磁盤容量相關。
四、思考
1、代碼中的b屬于棧區還是堆區?
1
2
3
4
|
void fun() { int *b = new int [14]; } |
b是在棧區的變量,由于b是一個局部變量,隨著函數域 的結束被釋放,不需要程序員自行釋放,盡管b使用new進行初始化,還是可以認為分配在棧區;
總結:
本次系統的從內存的基礎概念到內存分配進行了講解,內存是我們開發中最重要的一部分,往往邏輯上的錯誤就會造成內存泄漏,導致程序無法運行。或者一些分配內存的方式不夠細心,也會造成冗余內存的使用。在目前的很多嵌入式板子上,針對內存的接口是必備的,往往也都是基于malloc
修改;
還有一點需要注意,不管任何機器上運行程序,操作的都是虛擬內存,內部通過頁表定位到對應的物理內存。關于硬件方面的本質,如果做嵌入式端的話需要深入研究。
到此這篇關于C++內存分布及用法的文章就介紹到這了,更多相關C++內存內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/weixin_40620310/article/details/121754849