網站首頁 編程語言 正文
一、內存基礎
1、內存分布
通過下面一張圖看看C++的內存分布:
棧區:由編譯器自動分配與釋放,存放為程序運行時函數分配的局部變量、函數參數;棧內存分配運算內置于處理器的指令集中,效率很高,但是分配內存的容量有限;
堆區:由new
、malloc
分配的內存塊,釋放由應用程序控制,不需要編譯器釋放;如果程序員沒有對該內存進行釋放,程序結束后系統自動回收,堆的地方比棧大很多;
靜態區:存放的是static
的靜態變量和一些全局變量,特點是只讀、大小固定;靜態變量和全局變量的存儲期是一起的,一旦靜態區的內存被分配,要一直等到程序全部結束后才釋放;
2、棧區與堆區的區別
1、分配方式不同:棧區系統分配系統回收;堆區由程序員手動申請,需要求程序員自行回收,如果沒有回收,系統在程序結束后會進行回收,這種情況會造成內存泄漏;
2、生命周期不同:棧區生命周期是系統分配到系統回收,也就是在大括號內;堆區是從申請到釋放;
3、效率不同:主要原因是地址空間是否連續,棧區地址空間是連續的,效率會高一些;堆區地址空間不連續,需要遍歷鏈表才能找到最近的地址,效率會低一些;
4、內存碎片:堆區容易產生內存碎片,棧區不會;
5、生長方向不同:棧區申請空間的地址(表示地址的八個十六進制數)是從大到小的,堆區申請空間地址是從小到大的。棧區是先進后出的原則,類比棧結構的特點;
- 棧區特點:更好的局部性,對象自動銷毀;
- 堆區特點:運行期動態擴展,需要顯示釋放;
注意點:申請的空間是在堆區,變量本身是在棧區!
二、內存分配
1、內存分配方式
可操作的內存分配:
- 靜態存儲區分配:
static
靜態變量、全局變量; - 棧上分配:局部變量;
- 堆上分配:
new
、malloc
進行內存分配;
不可操作的內存分配:
內核區、代碼區、局部變量的分配也屬于系統分配;
2、new的用法
C++中通常使用new
、delete
來構造和銷毀對象;
使用new創建對象,返回的是對象的首地址,需要用指針接收:
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用法
根據分配的是單一對象還是數組,采用相應的方式銷毀;
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屬于棧區還是堆區?
void fun() { int *b = new int[14]; }
b是在棧區的變量,由于b是一個局部變量,隨著函數域 的結束被釋放,不需要程序員自行釋放,盡管b使用new進行初始化,還是可以認為分配在棧區;
總結:
本次系統的從內存的基礎概念到內存分配進行了講解,內存是我們開發中最重要的一部分,往往邏輯上的錯誤就會造成內存泄漏,導致程序無法運行。或者一些分配內存的方式不夠細心,也會造成冗余內存的使用。在目前的很多嵌入式板子上,針對內存的接口是必備的,往往也都是基于malloc
修改;
還有一點需要注意,不管任何機器上運行程序,操作的都是虛擬內存,內部通過頁表定位到對應的物理內存。關于硬件方面的本質,如果做嵌入式端的話需要深入研究。
原文鏈接:https://blog.csdn.net/weixin_40620310/article/details/121754849
相關推薦
- 2022-09-16 C語言庫函數getchar()新見解_C 語言
- 2022-07-27 C++詳細講解圖的拓撲排序_C 語言
- 2022-12-13 Android之rk3588?開發環境準備及問題解決方法_Android
- 2022-08-21 Golang中slice刪除元素的性能對比_Golang
- 2023-01-02 Python利用socket實現多進程的端口掃描器_python
- 2022-09-13 go語言中基本數據類型及應用快速了解_Golang
- 2023-05-06 Python中dilb和face_recognition第三方包安裝失敗的解決_python
- 2022-06-06 flutter 布局管理詳解
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支