淺談C++內存管理基礎知識
概述
內存管理的原理龐大而復雜,然而這些都被操作系統進行瞭封裝,並對外預留瞭API,這些api被c++調用,同時也被c++再次進行瞭封裝,再面向程序員預留出瞭語法特性的接口,作為使用c++的程序員,我們隻需要掌握c++預留的內存管理特性即可,就像我們開車不需要管變數箱、發動機是怎麼變速、點火的,我們隻需要掌握汽車給我們預留的接口,方向盤、剎車、油門如何使用即可。
c++程序容易出bug,主要就是因為內存管理部分的復雜性 ,java、python等語言提供瞭更多的封裝,所以降低瞭程序員的操作難度和犯錯的可能。就像自動檔的汽車一樣,沒有瞭離合,自然就不會因操作失誤把變速箱損壞。
c++可用內存
c語言的可用內存
在c語言中我們的可用內存主要分以下幾個區域:
- 棧,用於存放局部變量。
- 全局數據區/靜態數據區,用於存放全局變量和靜態局部變量。
- const數據區,該區域在內存中實際是沒有指定分區的,他存在於全局數據區或者棧中,const不能被修改是被編譯器限制的,在物理內存中根本就沒有隻讀類型的內存。所以有時候我們在討論分區的時候,不會提到const區,因為他根本就沒有獨立存在。
- 代碼段,當然是用來存放代碼,在linux下,我們的可執行代碼從rom中讀取到內存中執行,雖說內存可讀可寫,但是在操作系統的監控下,這段內存也是隻讀不寫的區域。
- 堆,c中的堆由malloc申請,free釋放,底層也是由操作系統提供給我們的程序的一段內存。
c++新增內存區域
c中的內存分區在c++中全部都存在,而c++新增瞭自由存儲區,使用new來申請,delet來釋放,實際和malloc申請的內存在一個區域,new使用內存示例如下:
int *p = new int; *p=6; cout << "*p=" << *p << endl; delete p;
new和malloc
linux平臺中new內部其實還是通過malooc來申請的內存,隻是附加做瞭些其他工作,例如調用類的構造函數來初始化。malloc返回的就像一塊荒地,需要你自己來規劃,而new返回的是一個修好基建的區域給你。
malloc |
new |
c庫函數 |
運算符、關鍵字 |
分配空間由傳參決定 |
大小由數據類型決定,編譯器自動計算 |
返回值void * |
明確的類型,申請啥返回啥 |
free釋放 |
delete、delet[ ]釋放 |
申請內存不初始化 |
可以隱式和顯示初始化 |
無構造函數 |
執行構造函數 |
申請失敗返回NULL |
申請失敗返回bad_alloc異常 |
智能指針引入
我們說,cpu決定瞭匯編指令、匯編決定瞭c和c++,所以c/c++的指針是天然的,用來支持匯編的間接尋址,可以說是cpu決定的指針。所以指針是無法避開的,指針的優勢是太靈活,劣勢也是太靈活,尤其是與動態內存、構造、析構結合使用後容易出錯,所以c++發明瞭一種智能指針,有程序員和專門設計的自動管理機制共同把控以減少出錯。這種自動管理機制在c中就有體現,如棧就是自動管理的結果。
智能指針是普通指針的升級版,本身具備指針的功能,且多出一些自動釋放資源的機制,當然,智能指針的使用會比普通指針要多消耗一些資源和開銷。在c++中,智能指針不是唯一的,有很多類型的智能指針,各有優劣和適應的場景。使用智能指針時,須按照設計,正確使用,否則容易導致災難。
智能指針的實現
將普通指針封裝為棧式復合指針對象,內部包含瞭除瞭真正指向目標的指針外還有些其他東西,如使用次數記錄等,要使用智能指針,我們需要註意以下問題:
- 將智能指針本身定義為局部(棧上),實現指針本身被自動回收的。
- 智能指針內部設計為當指針本身要被彈棧釋放時,執行事先掛接好的清理函數,也就是說智能指針內部應該有一個函數指針,指向我們的清理函數。
- 智能指針需要使用庫為其提供的方法和運算符來重載使用。
java延伸
java語言整體框架
為瞭保證知識的完整,我們簡單的介紹一下java的內容,來瞭解一些優質方法。
cpu ->系統內核 -> 應用層框架 -> java虛擬機 -> Java字節碼 -> java源碼
從上面的架構,我們能看出來,java比c/c++多瞭三層,java的源碼編譯輸出的並不是cpu可執行的機器碼,而是被編譯成java字節碼,這個東西完全是java自己定義的一種東西,隻能在JVM(java虛擬機)上運行, JVM再基於一些內核提供的框架來運行,所以說java是一種解釋性語言,他完全靠JVM進行解釋,而c/c++是編譯型語言,源碼直接編譯成cpu可執行的機器碼。正因為有瞭JVM,所以java可以跨平臺運行,哪裡有JVM哪裡就可以運行java,前提是不同平臺的JVM能相互兼容,java的運行穩定性取決於JVM。
java的垃圾回收機制
java有一個專門做垃圾回收的守護進程,GC線程,他內部使用GC機制和算法來得到生命周期結束的變量對象,把這些對象當成垃圾進行回收。
實際上垃圾回收並不是java的專利,其他語言,如c#也有類似的設計理念,典型的就是他們都沒有指針,其垃圾回收機制讓程序員免於考慮對象的生命周期和資源的申請與釋放,使得這門語言非常好學,其實垃圾回收機制的背後都是以效率和內存資源為代價,換來的不易出錯,簡單好用。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!