最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++學習之如何進行內(nèi)存資源管理

 更新時間:2023年05月21日 10:42:09   作者:會玩code  
與java、golang等自帶垃圾回收機制的語言不同,C++并不會自動回收內(nèi)存,這往往會導致內(nèi)存泄漏和內(nèi)存溢出等問題,所以掌握C++中的內(nèi)存管理技巧和工具是非常重要的,本文就來和大家詳細講講

前言

與java、golang等自帶垃圾回收機制的語言不同,C++并不會自動回收內(nèi)存。我們必須手動管理堆上內(nèi)存分配和釋放,這往往會導致內(nèi)存泄漏和內(nèi)存溢出等問題。而且,這些問題可能不會立即出現(xiàn),而是運行一段時間后,才會暴露出現(xiàn),排查也很困難。因此,了解和掌握C++中的內(nèi)存管理技巧和工具是非常重要的,可以提高程序性能、減少錯誤和增加安全性。

內(nèi)存分區(qū)

在C++中,將操作系統(tǒng)分配給程序的內(nèi)存空間按照用途劃分了代碼段、數(shù)據(jù)段、棧、堆幾個不同的區(qū)域,每個區(qū)域都有其獨特的內(nèi)存管理機制。

代碼區(qū)

代碼區(qū)是用于存儲程序代碼的區(qū)域,代碼段在程序真正執(zhí)行前就被加載到內(nèi)存中,在程序執(zhí)行期間,代碼區(qū)內(nèi)存不會被修改和釋放。

由于代碼區(qū)是只讀的,所以會被多個進程共享。在多個進程同時執(zhí)行同一個程序時,操作系統(tǒng)只需要將代碼段加載到內(nèi)存中一次,然后讓多個進程共享這個內(nèi)存區(qū)域即可。

數(shù)據(jù)段

數(shù)據(jù)段用于存儲靜態(tài)全局變量、靜態(tài)局部變量和靜態(tài)常量等靜態(tài)數(shù)據(jù)。在程序運行期間,數(shù)據(jù)段的大小固定不變,但其內(nèi)容可以被修改。按照變量是否被初始化。數(shù)據(jù)段可分為已初始化數(shù)據(jù)段和未初始化數(shù)據(jù)段。

C++中函數(shù)調(diào)用以及函數(shù)內(nèi)的局部變量的使用,都是通過棧這個內(nèi)存分區(qū)實現(xiàn)的。棧分區(qū)由操作系統(tǒng)自動分配和釋放,是一種"后進先出"的一種內(nèi)存分區(qū)。每個棧的大小是固定的,一般只有幾MB,所以如果棧變量太大,或者函數(shù)調(diào)用嵌套太深,容易發(fā)生棧溢出(stack overflow)。

先來一段示例代碼,看看C++是如何使用棧進行使用棧來進行函數(shù)調(diào)用的。

#include?<iostream>

void?inner(int?a)?{
????std::cout?<<?a?<<?std::endl;
}
void?outer(int?n)?{
?int?a?=?n?+?1;
????inner(a);
}

int?main()?{
????outer(4);
}

上面這段代碼運行過程中的棧變化如下圖

每當程序調(diào)用一個函數(shù)時,該函數(shù)的參數(shù)、局部變量和返回地址等信息會被壓入棧中。當函數(shù)執(zhí)行完畢,再將這些信息從棧中彈出。根據(jù)之前壓入的外層調(diào)用者壓入棧的返回地址,返回到外層調(diào)用者未執(zhí)行的代碼繼續(xù)執(zhí)行。

本地變量是直接存儲在棧上的,當函數(shù)執(zhí)行完成后,這些變量占用的內(nèi)存就會被釋放掉了。前面例子中的本地變量是簡單類型,在C++中稱為POD類型。對于帶有構造和析構函數(shù)的非POD類型變量,棧上的內(nèi)存分配同樣有效。編譯器會在合適的時機,插入對構造函數(shù)和析構函數(shù)的調(diào)用。

這里有個問題,當函數(shù)執(zhí)行發(fā)生異常時,析構函數(shù)還會被調(diào)用嗎?答案是會的,C++對于發(fā)生異常時對析構函數(shù)的調(diào)用稱為"棧展開"。通過下面這段代碼演示棧展開。

#include?<iostream>
#include?<string>

class?Obj?{
public:
????std::string?name_;
????Obj(const?std::string&?name):name_(name){std::cout?<<?"Obj()?"?<<?name_?<<?std::endl;};
????~Obj()?{std::cout?<<?"~Obj()?"?<<?name_?<<?std::endl;};
};


void?bar()?{
????auto?o?=?Obj{"bar"};
????throw?"bar?exception";
}

int?main()?{
????try?{
????????bar();
????}?catch?(const?char*?e)?{
????????std::cout?<<?"catch?Exception:?"?<<?e?<<?std::endl;
????}
}

執(zhí)行代碼的結果是:

Obj() bar
~Obj() bar
catch Exception: bar exception

可以發(fā)現(xiàn),發(fā)生異常時,bar函數(shù)中的本地變量o還是能被正常析構。

棧展開的過程實際上是異常發(fā)生時,匹配catch子句的過程。

  • 程序拋出異常,停止當前執(zhí)行的調(diào)用鏈,開始尋找與異常匹配的catch子句。
  • 如果異常發(fā)生在try中,則會首先檢查與該try塊匹配的catch子句。如果異常所在函數(shù)體沒有try捕獲異常。則會直接進入下一步。
  • 如果第二步未找到匹配的catch,則會在外層的try塊中查找,直到找到為止。
  • 如果到了最外層還沒有找到匹配的catch,也就是說異常得不到處理,程序會調(diào)用標準庫函數(shù)terminate終止函數(shù)的執(zhí)行。

在這期間,棧上所有的對象都會被自動析構。

堆是C++中用來存儲動態(tài)分配內(nèi)存的內(nèi)存分區(qū),堆內(nèi)存的分配和釋放需要手動管理,可以通過new/delete或malloc/free等函數(shù)進行分配和釋放。堆內(nèi)存的大小通常是不固定的,當我們需要動態(tài)分配內(nèi)存時,就可以使用堆內(nèi)存。

堆內(nèi)存由程序員手動分配和釋放,因此使用堆內(nèi)存需要注意內(nèi)存泄漏和內(nèi)存溢出等問題。當程序員忘記釋放已分配的內(nèi)存時,會導致內(nèi)存泄漏問題。而當申請的堆內(nèi)存超過了操作系統(tǒng)所分配給進程的內(nèi)存限制時,會導致內(nèi)存溢出問題。

C++程序絕大多數(shù)的內(nèi)存泄露,都是由于忘記調(diào)用delete/free來釋放堆上的資源。

還是上代碼

#include?<iostream>
#include?<string>

class?Obj?{
public:
????std::string?name_;
????Obj(const?std::string&?name):name_(name){std::cout?<<?"Obj()?"?<<?name_?<<?std::endl;};
????~Obj()?{std::cout?<<?"~Obj()?"?<<?name_?<<?std::endl;};
};

Obj*?makeObj()?{
?Obj*?obj?=?nullptr;
?try?{
??obj?=?new?Obj{"makeObj"};
??...
?}?catch(...)?{
??delete?obj;
??throw;
?}
?return?obj;
}

Obj*?foo()?{
?Obj*?obj?=?nullptr;
?try?{
??obj?=?makeObj();
??...
?}?catch(...)?{
??delete?obj;
?}
?return?obj;
}
int?main()?{
????Obj*?obj?=?foo();
????...
????delete?obj;
}

可以看到,由makeObj函數(shù)創(chuàng)建的堆變量obj, 在每個獲取該變量的上層調(diào)用中,都需要關心對該變量的處理。這無疑極大得增加了開發(fā)者的心智負擔。

RAII

想在堆上創(chuàng)建對象,又不想處理這么復雜的內(nèi)存釋放操作。C++沒有像java、golang其他語言創(chuàng)建一套垃圾回收機制,而是采用了一種特有的資源管理方式 --- RAII(Resource Acquisition Is Initialization,資源獲取即初始化)。

RAII利用棧對象在作用域結束后會自動調(diào)用析構函數(shù)的特點,通過創(chuàng)建棧對象來管理資源。在棧對象構造函數(shù)中獲取資源,在棧對象析構函數(shù)中負責釋放資源,以此保證資源的獲取和釋放。

下面給出一個通過RAII來自動釋放堆內(nèi)存的例子

#include?<iostream>

class?AutoIntPtr?{
public:
????AutoIntPtr(int*?p?=?nullptr)?:?ptr(p)?{}
????~AutoIntPtr()?{?delete?ptr;?}

????int&?operator*()?const?{?return?*ptr;?}
????int*?operator->()?const?{?return?ptr;?}

private:
????int*?ptr;
};

void?foo()?{
?AutoIntPtr?p(new?int(5));
????std::cout?<<?*p?<<?std::endl;?//?5
}

int?main()?{
????foo();
}

上面例子中,AutoIntPtr類封裝了一個動態(tài)分配的int類型的指針,它的構造函數(shù)用于獲取資源(ptr = p),析構函數(shù)用于釋放資源(delete ptr)。當AutoIntPtr超出作用域時,自動調(diào)用析構函數(shù)來釋放所包含的資源。

基于RAII,C++11引入了std::unique_ptrstd::shared_ptr等智能指針用于內(nèi)存管理類,使得內(nèi)存管理變得更加方便和安全。這些內(nèi)存管理類可以自動進行內(nèi)存釋放,避免了手動釋放內(nèi)存的繁瑣工作。值得一提的是,上面的AutoIntPtr就是一個簡化版的智能指針了。

在實際開發(fā)中,RAII的應用很廣。不僅僅用于自動釋放內(nèi)存。還可以用來關閉文件、釋放數(shù)據(jù)庫連接、釋放同步鎖等。

總結

本文介紹了C++中的內(nèi)存管理機制,包括內(nèi)存分區(qū)、棧、堆和RAII技術等內(nèi)容。通過學習本文,我們可以更好地掌握C++的內(nèi)存管理技巧,避免內(nèi)存泄漏和內(nèi)存溢出等問題。

以上就是C++學習之如何進行內(nèi)存資源管理的詳細內(nèi)容,更多關于C++內(nèi)存資源管理的資料請關注腳本之家其它相關文章!

相關文章

  • C++中std::partial_sort的使用小結

    C++中std::partial_sort的使用小結

    std::partial_sort?是?C++?標準庫中的一個算法,它可以對容器中的一部分元素進行排序,本文主要介紹了C++中std::partial_sort的使用小結,感興趣的可以了解一下
    2025-04-04
  • 實例分析一個簡單的Win32程序

    實例分析一個簡單的Win32程序

    這篇文章主要介紹了實例分析一個簡單的Win32程序,對于Win32應用程序的原理、執(zhí)行流程、實現(xiàn)方法主要環(huán)節(jié)都做了較為詳細的分析,有助于讀者深入理解Windows應用程序設計,需要的朋友可以參考下
    2014-09-09
  • 一篇文章帶你了解C++面向?qū)ο缶幊?-繼承

    一篇文章帶你了解C++面向?qū)ο缶幊?-繼承

    這篇文章主要介紹了解析C++面對象編程--繼承的運用,是C++入門學習中的基礎知識,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-08-08
  • C語言一看就懂的指針與結構體介紹

    C語言一看就懂的指針與結構體介紹

    指針提供了對地址操作的一種方法,因此,使用指針可使得C語言能夠更高效地實現(xiàn)對計算機底層硬件的操作。另外,通過指針可以更便捷地操作數(shù)組。C數(shù)組允許定義可存儲相同類型數(shù)據(jù)項的變量,結構是C編程中另一種用戶自定義的可用的數(shù)據(jù)類型,它允許您存儲不同類型的數(shù)據(jù)項
    2022-04-04
  • Opencv實現(xiàn)對象提取與測量

    Opencv實現(xiàn)對象提取與測量

    這篇文章主要為大家詳細介紹了基于Opencv實現(xiàn)對象提取與測量,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • C++中實現(xiàn)矩陣的加法和乘法實例

    C++中實現(xiàn)矩陣的加法和乘法實例

    這篇文章主要介紹了C++中實現(xiàn)矩陣的加法和乘法實例的相關資料,需要的朋友可以參考下
    2017-03-03
  • C語言實現(xiàn)線索二叉樹的定義與遍歷示例

    C語言實現(xiàn)線索二叉樹的定義與遍歷示例

    這篇文章主要介紹了C語言實現(xiàn)線索二叉樹的定義與遍歷,結合具體實例形式分析了基于C語言的線索二叉樹定義及遍歷操作相關實現(xiàn)技巧與注意事項,需要的朋友可以參考下
    2017-06-06
  • C語言在頭文件中定義const變量詳解

    C語言在頭文件中定義const變量詳解

    這篇文章主要介紹了C語言在頭文件中定義const變量詳解的相關資料,需要的朋友可以參考下
    2017-05-05
  • 利用Matlab制作一款3D版2048小游戲

    利用Matlab制作一款3D版2048小游戲

    2048作為一款經(jīng)典的小游戲,相信很多人都玩過吧?但是3D版的2048不知道有沒有人玩過呢?本文將用Matlab制作一個3D版的2048小游戲,快跟隨小編一起動手試一試吧
    2022-02-02
  • C語言實現(xiàn)數(shù)字連連看

    C語言實現(xiàn)數(shù)字連連看

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)數(shù)字連連看游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論

邢台县| 靖远县| 大名县| 来安县| 灵丘县| 贺州市| 潮州市| 东兴市| 湖南省| 和林格尔县| 金川县| 叶城县| 遵义县| 盐山县| 安阳市| 渝中区| 峡江县| 宝应县| 吉林省| 罗甸县| 九台市| 唐海县| 久治县| 马边| 内乡县| 沙田区| 灵台县| 新兴县| 西安市| 张北县| 玉龙| 印江| 高碑店市| 绩溪县| 南岸区| 舟曲县| 三亚市| 杂多县| 黄平县| 德清县| 航空|