C++:內存管理

內存分布:

首先我們需要了解的是C/C++中內存區域的劃分:

1. 棧又叫堆棧--非靜態局部變量/函數參數/返回值等等,棧是向下增長的:先調用的地址比后調用的地址大。
2. 內存映射段是高效的I/O映射方式,用于裝載一個共享的動態內存庫。用戶可使用系統接口
創建共享共享內存,做進程間通信。
3. 堆用于程序運行時動態內存分配,堆是可以上增長的:先調用的地址比后調用的地址小。
4.?數據段--存儲全局數據和靜態數據。
5. 代碼段--可執行的代碼/只讀常量。

當我們懂了內存分布,可以嘗試練習:

是不是前面還算簡單,下面就寫懵圈了!

解析:

? ? ? ? char2是定義在棧上的,它將在常量區的“abcd”拷貝的一份到數組中,,所以解引用(數組名是數組的首地址)還是是在棧上;

? ? ? ? pChar3是一個指向常量區的“abcd”的一個指針,定義在棧上,解引用后就是常量區的“abcd”所以解引用在常量區;

? ? ? ? ptr1定義在棧上,但是malloc開辟的空間在堆上,所以解引用是在堆上;

棧和堆的區別:?

棧和堆的區別:

????????棧:由編譯器自動分配并且出了作用域就釋放,一般存儲函數的參數局部變量等。
????????堆:由我們通過開辟的空間分配,需要我們手動釋放,若程不釋放則系統釋放。

1、申請內存的方式:
棧:由編譯器自動分配,如變量的聲明的同時會開辟空間。

堆:由程序員申請,需要制定需要的大小(動態分配)。
2、系統響應的不同:

棧:只要系統剩余空間大于申請內存,系統就會提供,否則程序會崩潰流:棧溢出。

堆:遍歷空閑地址鏈表,找到符合要求的,就將該地址分配給程序,內存的首地址記錄分配的大小(方便delete)。

3、空間大小不同:
棧:連續的,編譯時就確定的大小;
堆:不連續,他的上限決定于系統中有效的虛擬內存。
4、執行效率的不同:
棧:由系統分配,速度快;
堆:程序員分配,速度慢,容易產生內存碎片,需要多少開辟多少。

C語言中動態內存管理方式:malloc/calloc/realloc/free

malloc/calloc/realloc的區別:

? ? ? ? 1.malloc和realloc分配好內存空間后不會對空間初始化,calloc會對空間全部初始化為0.

? ? ? ? 2.參數不同:malloc(需要開辟的大小)、calloc(需要開辟個數,每個的大小)、realloc(原來的指針,新的內存塊大小)。

? ? ? ? 3.它們空間分配失敗的返回值地址都為NULL;

? ? ? ? 4.它們都需要free釋放內存,否則會造成內存泄漏等問題。

C++內存管理方式

????????C語言內存管理方式在C++中可以繼續使用,但有些地方就無能為力,而且使用起來比較麻煩,因此C++又提出了自己的內存管理方式:通過new和delete操作符進行動態內存管理。

new/delete操作內置類型

注意:在申請自定義類型的空間時,new會調用構造函數,delete會調用析構函數,而malloc與free不會。

#include <iostream>
using namespace std;class Stack
{
public:Stack(int capacity = 4){cout << "構造函數" << endl;_capacity = capacity;_a = new int[_capacity];_top = 0;}~Stack(){cout << "析構函數" << endl;delete[] _a;_a = nullptr;_top = 0;_capacity = 0;}
private:int* _a;int _capacity;int _top;
};int main()
{Stack s1;//Stack* p1 = new Stack;//1.new先開辟一個Stack大小的空間;2.然后調用構造函數在開辟一個棧的空間//delete p1;//1.先釋放構造函數開辟的空間;2.再釋放new開辟的Stack的空間//Stack* p2 = (Stack*)operator new(sizeof(Stack));//沒有去調用構造函數初始化//operator delete(p2);//沒有去調用析構函數,導致內存泄漏:給棧開辟的空間沒有釋放//Stack* p3 = new Stack[10];//這里開辟的空間會多開4個,用于存放開辟的數量,便于delete使用delete[] p3;//delete p3;//空間不能局部釋放:直接去釋放Stack的空間,前面還有用于記錄數量的空間,所以程序崩潰return 0;
}

操作自定義類型:

?new/delete 和 malloc/free最大區別是 new/delete對于【自定義類型】除了開空間還會調用構造函數和析構函數!!!

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}//~A()//{//	cout << "~A():" << this << endl;//}private:int _a;
};int main()
{A* p4 = new A[10];//delete p4;//如果沒有定義析構是不會出錯:因為編譯器的優化認為不需要調用析構,所以沒有多開辟空間來記錄開辟的個數free(p4);//同理return 0;
}
//通過上面兩個程序的比較:new/delete  new[]/delete[] malloc/free 一定要配對使用,否則結果是未定義

注意:

????????申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續的空間,使用
new[]和delete[],注意:new和delete匹配起來使用。

了解operator new與operator delete函數

????????new和delete是用戶進行動態內存申請和釋放的操作符,operator new 和operator delete是系統提供的全局函數new在底層調用operator new全局函數來申請空間,delete在底層通過operator delete全局函數來釋放空間。

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

可以看到operator new?函數實際還是通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間失敗,嘗試執行空間不足應對措施,如果改應對措施用戶設置了,則繼續申請,否則拋異常。可以理解為:為了解決C語言中將malloc失敗的NULL設置為0,導致一些特殊場景的錯誤,所以將malloc進行封裝了,對malloc失敗進行異常拋出。

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 delete函數本質還是通過free來釋放空間,

????????通過上述兩個全局函數的實現知道,operator new 實際也是通過malloc來申請空間,如果malloc申請空間成功就直接返回,否則執行用戶提供的空間不足應對措施,如果用戶提供該措施就繼續申請,否則就拋異常。operator delete 最終是通過free來釋放空間的。

new和delete的實現原理

內置類型:

????????如果申請的是內置類型的空間,new和malloc,delete和free基本類似,不同的地方是:
new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL。

自定義類型:

new的原理:
????????1. 調用operator new函數申請空間
????????2. 在申請的空間上執行構造函數,完成對象的構造
delete的原理:
????????1. 在空間上執行析構函數,完成對象中資源的清理工作
????????2. 調用operator delete函數釋放對象的空間
new T[N]的原理:
????????1. 調用operator new[]函數,在operator new[]中實際調用operator new函數完成N個對象空間的申請:
????????2. 在申請的空間上執行N次構造函數
delete[]的原理:
????????1. 在釋放的對象空間上執行N次析構函數,完成N個對象中資源的清理
????????2. 調用operator delete[]釋放空間,實際在operator delete[]中調用operator delete來釋放空間

定位new表達式(placement-new)

定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象。
使用格式:
????????new (place_address) type或者new (place_address) type(initializer-list)
????????place_address必須是一個指針,initializer-list是類型的初始化列表

使用場景:
????????定位new表達式在實際中一般是配合內存池使用。因為內存池分配出的內存沒有初始化,所以如果是自定義類型的對象,需要使用new的定義表達式進行顯示調構造函數進行初始化

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}//~A()//{//	cout << "~A():" << this << endl;//}private:int _a;
};int main()
{A a1;//自動調用構造函數//構造函數可以顯示調用嗎?A* p1 = (A*)operator new(sizeof(A));//不能下面這樣顯示調用構造函數//p1->A(1);//但是可以用定位new顯示調用構造函數new(p1)A(1);//析構函數就可以顯示調用p1->~A();operator delete(p1);return 0;
}

特別需要理解:malloc/free和new/delete的區別

malloc/free和new/delete:

共同點是都是從堆上申請空間,并且需要用戶手動釋放。

不同的地方是
????????1. malloc和free是函數,new和delete是操作符;
????????2. malloc申請的空間不會初始化,new可以初始化;
????????3. malloc申請空間時,需要手動計算空間大小并傳遞,new只需在其后跟上空間的類型即可,如果是多個對象,[]中指定對象個數即可;
????????4. malloc的返回值為void*, 在使用時必須強轉,new不需要,因為new后跟的是空間的類型;
????????5. malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲異常;
????????6. 申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數與析構函數,而new在申請空間后會調用構造函數完成對象的初始化,delete在釋放空間前會調用析構函數完成空間中資源的清理.

本人實力有限可能對一些地方解釋和理解的不夠清晰,可以自己嘗試讀代碼,或者評論區指出錯誤,望海涵!

感謝大佬們的一鍵三連!?感謝大佬們的一鍵三連!?感謝大佬們的一鍵三連!

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/166590.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/166590.shtml
英文地址,請注明出處:http://en.pswp.cn/news/166590.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

百度文心一言(千帆大模型)聊天API使用指導

開篇不得不吐槽下百度&#xff0c;百度智能云平臺首頁跳轉千帆大模型平臺的按鈕太多了&#xff0c;不同按鈕跳轉不同的子頁面&#xff0c;不熟悉的&#xff0c;能把人找懵。入口太多&#xff0c;就導致用戶不知道從何開始。本文就從一個前端開發人員的角度&#xff0c;教大家快…

【深度學習】基于深度學習的超分辨率圖像技術一覽

超分辨率(Super-Resolution)即通過硬件或軟件的方法提高原有圖像的分辨率&#xff0c;圖像超分辨率是計算機視覺和圖像處理領域一個非常重要的研究問題&#xff0c;在醫療圖像分析、生物特征識別、視頻監控與安全等實際場景中有著廣泛的應用。 SR取得了顯著進步。一般可以將現有…

為什么,word文件在只讀模式下,仍然能編輯?

Word文檔設置了只讀模式&#xff0c;是可以編輯的&#xff0c;但是當我們進行保存的時候就會發現&#xff0c;word提示需要重命名并選擇新路徑才能夠保存。 這種操作&#xff0c;即使可以編輯文字&#xff0c;但是原文件是不會受到影響的&#xff0c;編輯之后的word文件會保存到…

torch常用和預期輸入輸出

import torch import torch.nn as nn import torch.nn.functional as F nn中定義的是類&#xff0c;functional里面定義的是函數操作。 輸出shape的計算公式&#xff1a; o u t _ s h a p e r o u n d _ m o d e ( i n _ s h a p e 2 ? p a d d i n g ? k e r n e l _ s…

20231124給RK3399的挖掘機開發板在Andorid10下加鼠標右鍵返回

20231124給RK3399的挖掘機開發板在Andorid10下加鼠標右鍵返回 2023/11/24 12:19 百度&#xff1a;RK3399 Android10 右鍵返回 https://blog.csdn.net/danhu/article/details/122467256 android9/android10 鼠標右鍵返回(已驗證) danhu 于 2022-01-13 09:46:42 發布 android10 …

Echarts 大屏注冊自定義地圖解析文件流報錯問題解決

效果圖: 1、首先通過后臺接口獲取到SVG圖片的文件流,postman能夠正確解析出文件流,前端調用api時需要設置返回的響應格式為image/svg+xml格式,否則解析失敗 拿到文件流后是這樣的 <?xml version="1.0" encoding="utf-8"?> <!-- Generator: …

【深度學習】P1 深度學習基礎框架 - 張量 Tensor

深度學習基礎框架 張量 Tensor 張量數據操作導入創建張量獲取張量信息改變張量張量運算 張量與內存 張量 Pytorch 是一個深度學習框架&#xff0c;用于開發和訓練神經網絡模型。 而其核心數據結構&#xff0c;則是張量 Tensor&#xff0c;類似于 Numpy 數組&#xff0c;但是可…

AI制作的《大多數普通女孩的一生》——公開教程和工作流

內容來源&#xff1a;JiamigouCn ?這周由AI制作的《大多數普通女孩的一生》&#xff0c;在抖音爆火&#xff0c;獲得新華網轉發。到目前為止&#xff0c;全網還沒有公開教程和工作流&#xff0c;需要花費800-2000購買。 本著AI社區共享原則&#xff0c;我委托公眾號“楚思智能…

小學生古詩文大會復賽在線模擬新增刷題版和闖關版,幫助孩子沖刺

小學生古詩文大會明天就要開始了&#xff0c;剛剛古詩文大會主辦方也正式發布了通知&#xff0c;總體安排、操作指引和我之前發布的一樣&#xff1a;2023年11月25日小學生古詩文大會復選&#xff08;復賽&#xff09;答題操作手冊 為了幫助參加復選&#xff08;復賽&#xff09…

NFC技術簡介

NFC簡介 NFC(近場通信&#xff0c;Near Field Communication&#xff09;是一種短距高頻的無線電技術&#xff0c;由非接觸式射頻識別(RFID)演變而來。 NFC工作頻率為13.56Hz&#xff0c;通常只有在距離不超過4厘米時才能啟動連接&#xff0c;其傳輸速度有106 Kbit/秒、212 Kb…

從文本生成到數據增強:探索 AI 前沿的開源套件 | 開源專題 No.44

Significant-Gravitas/AutoGPT Stars: 150.4k License: MIT AutoGPT 是開源 AI 代理生態系統的核心工具包。它采用模塊化和可擴展的框架&#xff0c;使您能夠專注于以下方面&#xff1a; 構建 - 為驚人之作打下基礎。測試 - 將您的代理調整到完美狀態。查看 - 觀察進展成果呈…

【Mybatis源碼】反射 - MetaClass

前面我們介紹了Reflector類,Reflector主要完成了Class類中Setter、Getter方法的封裝,可以使用屬性獲取對應的Getter、Setter方法完成方法的調用,同時也可以判斷屬性是否存在,是否存在Getter、Setter方法。 使用Reflector解決了訪問Class類中屬性的問題,但是如果屬性是成員…

HandBrake 1.7 近日發布

導讀HandBrake 1.7 近日發布&#xff0c;作為這個開源、免費和跨平臺視頻轉碼器應用程序的重大更新&#xff0c;適用于 GNU/Linux、macOS 和 Windows 系統。 在 HandBrake 1.6 發布近一年后&#xff0c;HandBrake 1.7 版本為 Linux 用戶提供了許多好處&#xff0c;包括視頻摘要…

C語言第二十八彈--輸入一個非負整數,返回組成它的數字之和

C語言求輸入一個非負整數&#xff0c;返回組成它的數字之和 方法一、遞歸法 思路&#xff1a;設計一個初始條件&#xff0c;通過遞歸獲取非負整數的個位&#xff0c;不斷接近遞歸條件即可。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h>int DigitSum(int n) {…

PGZ-SBV系列項目介紹、技術選型、技術優勢(AIO內部版)All-In-One

前情提示 項目孵化于2014年,內部正式發行于2015.隨著業務需求,部分內部高級功能逐步對外開放支持多行業(保險、金融、餐飲、旅游、電商、直播等等),多架構,支持AI集成,支持協同,只要你想到的均可集成、均已內置高安全,高可用,多技術解決方案包含av版本、gf低代碼版、…

ubuntu22.04 arrch64版在線安裝maven

腳本 if type -p mvn; thenecho "maven has been installed."elsecd /home/zenglgwget https://dlcdn.apache.org/maven/maven-3/3.9.5/binaries/apache-maven-3.9.5-bin.tar.gz --no-check-certificatetar vxf apache-maven-3.9.5-bin.tar.gz rm -rf /usr/local/mav…

springboot+vue基本微信小程序的劇本殺游戲設計與實現

項目介紹 首先,論文一開始便是清楚的論述了小程序的研究內容。其次,剖析系統需求分析,弄明白“做什么”,分析包括業務分析和業務流程的分析以及用例分析,更進一步明確系統的需求。然后在明白了小程序的需求基礎上需要進一步地設計系統,主要包羅軟件架構模式、整體功能模塊、數…

通過內網穿透本地MariaDB數據庫,實現在公網環境下使用navicat圖形化工具

公網遠程連接MariaDB數據庫【cpolar內網穿透】 文章目錄 公網遠程連接MariaDB數據庫【cpolar內網穿透】1. 配置MariaDB數據庫1.1 安裝MariaDB數據庫1.2 測試局域網內遠程連接 2. 內網穿透2.1 創建隧道映射2.2 測試隨機地址公網遠程訪問3. 配置固定TCP端口地址3.1 保留一個固定的…

微信小程序 修改默認單選,多選按鈕樣式

微信小程序 修改默認單選&#xff0c;多選按鈕樣式 1.在微信開發者文檔中復制一份單選或者多選的代碼 <!--pages/index3/index.wxml--> <radio-group bindchange"radioChange"><label class"weui-cell weui-check__label" style"dis…

小程序:project.config.json / project.private.config.json / 項目配置文件 /拉取代碼產生沖突 / 如何解決

一、理解project.config.json / project.private.config.json project.config.json 文件是項目的配置文件&#xff0c;它包含了關于小程序的一些基本信息&#xff0c;例如小程序的名稱、App ID、開發者信息以及頁面路徑等。這個文件一般不會被提交到版本控制系統中&#xff0c;…