柚子快報(bào)激活碼778899分享:c語言 C/C++內(nèi)存詳解
柚子快報(bào)激活碼778899分享:c語言 C/C++內(nèi)存詳解
歡迎來到?破曉的歷程的 博客
??不負(fù)時光,不負(fù)己??
文章目錄
C/C++內(nèi)存模型C語言動態(tài)內(nèi)存管理mallocrealloccallocfree
C++動態(tài)內(nèi)存申請new 操作符delete 操作符注意事項(xiàng)用法示例
operator new和operator delete函數(shù)內(nèi)存泄露
C/C++內(nèi)存模型
讓我們先來看看這段代碼:
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
你知道上面代碼中定義的變量分別存儲在內(nèi)存中的哪些部分嗎? 說明一下:
棧又叫做堆棧,用來存儲非靜態(tài)局部變量、函數(shù)參數(shù)和返回值等等,棧是向下增長的。內(nèi)存映射段是高效的IO映射的方式,用來裝載一個共享的動態(tài)內(nèi)存庫,用戶可調(diào)用接口創(chuàng)建共享內(nèi)存,用于進(jìn)程間通信。堆用于存儲運(yùn)行時動態(tài)內(nèi)存分配,堆是向上增長的。我們使用malloc動態(tài)內(nèi)存申請的空間在堆上。包括我們一會兒講到的new也是如此。數(shù)據(jù)段又叫做靜態(tài)區(qū),用于存儲全局變量和靜態(tài)數(shù)據(jù)。代碼段又叫做常量區(qū),用來存儲可執(zhí)行的代碼和只讀常量。
C語言動態(tài)內(nèi)存管理
malloc、realloc、calloc 和 free 是C語言中用于動態(tài)內(nèi)存管理的標(biāo)準(zhǔn)庫函數(shù),它們定義在
malloc
malloc(Memory Allocation)函數(shù)用于動態(tài)分配一塊指定大小的內(nèi)存區(qū)域。其原型為:
void* malloc(size_t size);
size 參數(shù)指定了要分配的字節(jié)數(shù)。如果分配成功,返回指向分配的內(nèi)存區(qū)域的指針;如果分配失敗,則返回 NULL。
使用 malloc 分配的內(nèi)存區(qū)域是未初始化的,其內(nèi)容是未定義的。
realloc
realloc(Re-Allocation)函數(shù)用于重新調(diào)整之前通過 malloc、calloc 或 realloc 分配的內(nèi)存區(qū)域的大小。其原型為:
void* realloc(void* ptr, size_t size);
ptr 是指向要調(diào)整大小的內(nèi)存區(qū)域的指針。如果 ptr 是 NULL,則 realloc 的行為類似于 malloc,分配一塊新的內(nèi)存區(qū)域。size 是新的大小。如果分配成功,返回指向新內(nèi)存區(qū)域的指針(可能與原指針相同,也可能不同)。如果失敗,則返回 NULL,但原內(nèi)存區(qū)域不會被釋放。
calloc
calloc(Contiguous Allocation)函數(shù)也用于動態(tài)分配內(nèi)存,但它還會將分配的內(nèi)存區(qū)域初始化為零。其原型為:
void* calloc(size_t num, size_t size);
num 指定了要分配的元素?cái)?shù)量。size 指定了每個元素的大?。ㄒ宰止?jié)為單位)。calloc 分配的內(nèi)存總大小是 num * size。分配的內(nèi)存區(qū)域會被初始化為零。如果分配成功,返回指向分配的內(nèi)存區(qū)域的指針;如果失敗,則返回 NULL。
free
free 函數(shù)用于釋放之前通過 malloc、calloc 或 realloc 分配的內(nèi)存區(qū)域。其原型為:
void free(void* ptr);
ptr 是指向要釋放的內(nèi)存區(qū)域的指針。一旦內(nèi)存被釋放,ptr 指針就成為懸垂指針(dangling pointer),不應(yīng)再被使用。嘗試訪問已釋放的內(nèi)存區(qū)域是未定義行為,可能導(dǎo)致程序崩潰或數(shù)據(jù)損壞。
總的來說,malloc、realloc、calloc 和 free 提供了在C語言中進(jìn)行動態(tài)內(nèi)存管理的核心功能,允許程序在運(yùn)行時靈活地管理內(nèi)存資源。
面試題:malloc、realloc和calloc有什么區(qū)別? malloc:動態(tài)申請空間,但不對空間進(jìn)行初始化 realloc:對申請過的內(nèi)存空間進(jìn)行擴(kuò)容處理。 calloc:申請空間的同時進(jìn)行初始化處理,calloc=malloc+memset。
C++動態(tài)內(nèi)存申請
C語言的動態(tài)內(nèi)存申請函數(shù)對于C++依舊可以使用。但也引入了新的動態(tài)內(nèi)存申請方式:new、delete。
注意:malloc、realloc和calloc屬于函數(shù),但是new和delete屬于操作符
new 操作符
new 操作符用于在堆(heap)上動態(tài)分配內(nèi)存,并調(diào)用對象的構(gòu)造函數(shù)(如果有的話)。其基本語法有兩種形式:
為單個對象分配內(nèi)存: TypeName* pointer = new TypeName(initializer);
這里,TypeName 是要創(chuàng)建的對象類型,initializer 是傳遞給對象構(gòu)造函數(shù)的參數(shù)(如果構(gòu)造函數(shù)需要的話;如果構(gòu)造函數(shù)沒有參數(shù)或?qū)ο箢愋褪腔緮?shù)據(jù)類型,則可以省略)。pointer 是一個指向新創(chuàng)建對象的指針。 為對象數(shù)組分配內(nèi)存: TypeName* array = new TypeName[arraySize];
這里,TypeName 是數(shù)組元素的類型,arraySize 是數(shù)組中元素的數(shù)量。array 是一個指向數(shù)組第一個元素的指針。注意,對于數(shù)組,不會調(diào)用構(gòu)造函數(shù)來初始化每個元素(除非元素類型是類類型且該類提供了默認(rèn)構(gòu)造函數(shù)),而是進(jìn)行默認(rèn)初始化(對于類類型,調(diào)用默認(rèn)構(gòu)造函數(shù);對于內(nèi)置類型,不進(jìn)行初始化)。
delete 操作符
delete 操作符用于釋放之前通過 new 分配的內(nèi)存,并調(diào)用對象的析構(gòu)函數(shù)(如果有的話)。其語法也有兩種形式,對應(yīng)于 new 的兩種用法:
釋放單個對象: delete pointer;
這里,pointer 是指向之前通過 new 分配的內(nèi)存的指針。使用 delete 后,pointer 變成了懸垂指針,不應(yīng)再被使用。 釋放對象數(shù)組: delete[] array;
這里,array 是指向之前通過 new[] 分配的內(nèi)存的指針。注意,對于數(shù)組,必須使用 delete[] 而不是 delete 來釋放內(nèi)存,以確保為每個元素調(diào)用析構(gòu)函數(shù)(如果元素類型是類類型的話)。
注意事項(xiàng)
使用 new 分配的內(nèi)存必須使用 delete(或 delete[])來釋放,以避免內(nèi)存泄漏。釋放內(nèi)存后,指針變成懸垂指針,不應(yīng)再被解引用或用于其他內(nèi)存操作。對于類類型的對象,new 會自動調(diào)用構(gòu)造函數(shù),delete 會自動調(diào)用析構(gòu)函數(shù)。這是 new/delete 與 malloc/free 的一個重要區(qū)別。如果 new 表達(dá)式失?。ɡ纾捎趦?nèi)存不足),它會拋出 std::bad_alloc 異常(在
用法示例
#include
using namespace std;
int main()
{
int* p1 = new int(10);//申請一個空間
int* p2 = new int[10];//申請一個數(shù)值
delete p1;//釋放一個空間
delete []p2;//釋放一個數(shù)組
}
思考一下:既然已經(jīng)有了malloc等函數(shù),為什么還要設(shè)計(jì)出new這些操作符呢?new相對于malloc有哪些優(yōu)勢呢?
當(dāng)申請的空間類型為內(nèi)置類型時,malloc和new的功能相同。如果內(nèi)存申請失敗,malloc會返回0,而new則會選擇拋異常當(dāng)申請的類型為自定義類型時,malloc和new的功能就有些差別了。接下來我們就介紹一下二者之間的差別。
讓我們先來看看這段代碼:
class A
{
public:
A()
{
_a = 1;
cout << "A()" << endl;
}
public:
int _a;
};
int main()
{
A* a1 = (A*)malloc(sizeof(A));
cout << "--------------------------------------" << endl;
A* a2 = new A;
}
運(yùn)行一下,我們會發(fā)現(xiàn): 說明一下: 對于自定義類型的對象,例如類對象,new對象的同時會調(diào)用構(gòu)造函數(shù)對對象進(jìn)行構(gòu)造,delete對象的同時會調(diào)用析構(gòu)函數(shù)對對象進(jìn)行析構(gòu)。
operator new和operator delete函數(shù)
new和delete是用戶進(jìn)行動態(tài)內(nèi)存申請和釋放的操作符,operator new 和operator delete是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來申請空間,delete在底層通過operator delete全局函數(shù)來釋放空間。
operator new和operator delete在用法上和malloc和free完全一樣,都會在堆上申請空間
用法如下:
int* p = (int*)operator new(sizeof(int) * 10);//申請10個int類型大小的空間
operator delete (p);//對申請的空間進(jìn)行釋放
其在用法上等價(jià)于:
int* q = (int*)malloc(sizeof(int) * 10);
free(p);
盡管operator new和malloc在用法和作用上非常相似。但是仍然有不同之處?
不同之處有如下:
處理錯誤的方式不同,讓我們看看如下的代碼:
總結(jié)一下: 在申請失敗的情況下,malloc返回0,operator new拋異常。
malloc VS operator new VS new
operator new=malloc+拋異常new=operator+初始化
內(nèi)存泄露
什么是內(nèi)存泄露?內(nèi)存泄露有什么???
什么是內(nèi)存泄漏:內(nèi)存泄漏指因?yàn)槭韬龌蝈e誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。內(nèi)存泄漏并不是指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,因?yàn)樵O(shè)計(jì)錯誤,失去了對該段內(nèi)存的控制,因而造成了內(nèi)存的浪費(fèi)。內(nèi)存泄漏的危害:長期運(yùn)行的程序出現(xiàn)內(nèi)存泄漏,影響很大,如操作系統(tǒng)、后臺服務(wù)等等,出現(xiàn)內(nèi)存泄漏會導(dǎo)致響應(yīng)越來越慢,最終卡死。
內(nèi)存泄露的分類
C/C++程序中一般我們關(guān)心兩種方面的內(nèi)存泄漏:
堆內(nèi)存泄漏(Heap leak) 堆內(nèi)存指的是程序執(zhí)行中依據(jù)須要分配通過malloc / calloc / realloc / new等從堆中分配的一塊內(nèi)存,用完后必須通過調(diào)用相應(yīng)的 free或者delete 刪掉。假設(shè)程序的設(shè)計(jì)錯誤導(dǎo)致這部分內(nèi)存沒有被釋放,那么以后這部分空間將無法再被使用,就會產(chǎn)生Heap Leak。系統(tǒng)資源泄漏 指程序使用系統(tǒng)分配的資源,比方套接字、文件描述符、管道等沒有使用對應(yīng)的函數(shù)釋放掉,導(dǎo)致系統(tǒng)資源的浪費(fèi),嚴(yán)重可導(dǎo)致系統(tǒng)效能減少,系統(tǒng)執(zhí)行不穩(wěn)定。
如何避免內(nèi)存泄露
工程前期良好的設(shè)計(jì)規(guī)范,養(yǎng)成良好的編碼規(guī)范,申請的內(nèi)存空間記著匹配的去釋放。ps: 這個理想狀態(tài)。但是如果碰上異常時,就算注意釋放了,還是可能會出問題。需要下一條智 能指針來管理才有保證。采用RAII思想或者智能指針來管理資源。有些公司內(nèi)部規(guī)范使用內(nèi)部實(shí)現(xiàn)的私有內(nèi)存管理庫。這套庫自帶內(nèi)存泄漏檢測的功能選項(xiàng)。出問題了使用內(nèi)存泄漏工具檢測。ps:不過很多工具都不夠靠譜,或者收費(fèi)昂貴。 總結(jié)一下:
內(nèi)存泄漏非常常見,解決方案分為兩種:1、事前預(yù)防型。如智能指針等。2、事后查錯型。如泄 漏檢測工具。
柚子快報(bào)激活碼778899分享:c語言 C/C++內(nèi)存詳解
推薦閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。