寫乙個好的c++程式,我們要懂得好多東西,比如說最基本的物件導向程式設計思想,c++的封裝、繼承、多型機制,設計模式等,還有乙個很重要的內容便是效能優化,像c/c++這種接近底層的語言,追求的就是效能,與之相關的一項內容便是記憶體管理,記憶體分配要合理,禁止破壞記憶體,不能有記憶體洩漏,操作不好的話,程式可能會越執行越慢,要不就是莫名其妙的crash,於是令人頭疼的bug排查就這樣開始了。
在c++中,記憶體分為5個區:堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。
堆:由new分配的記憶體塊,分配成功後需要我們在適當的時候通過delete釋放記憶體,為了避免記憶體洩漏,new和delete要成對使用。
棧:執行函式時,函式內的區域性變數(也叫自動變數)在棧上建立儲存單元,函式執行結束時這些儲存單元被自動釋放,正因如此,函式返回區域性變數的指標或引用是錯誤的。
自由儲存區:由malloc等函式分配的記憶體塊,與堆類似,但記憶體釋放是用free來完成的,malloc/free與new/delete的區別是前者屬於庫函式,而後者是操作符,除了分配/釋放記憶體外,還會呼叫類的構造/析構函式。
全域性/靜態儲存區:全域性變數和靜態變數被分配到同一塊儲存區,生命週期和作用域與區域性變數不同。
常量儲存區:顧名思義,記憶體中存放的是常量,不允許修改。
堆、棧是經常提及的兩個記憶體塊,主要區別體現在以下幾個方面。
管理方式:棧由編譯器自動管理,棧上的變數離開作用域之後記憶體被自動**,而堆由我們自己管理,動態建立與釋放記憶體,管理起來較為複雜。
空間大小:棧空間較小,堆空間則很大。
碎片問題:棧的資料結構形式是後進先出,記憶體空間是一塊連續的區域,不會有記憶體碎片問題,而堆則不同,頻繁的new/delete會造成記憶體空間的不連續,從而產生堆碎片,影響程式效能。
分配方式:棧有兩種分配方式,靜態分配和動態分配,靜態分配由編譯器完成,如區域性變數的記憶體分配和釋放,動態分配通過呼叫alloca函式實現,但記憶體釋放是由編譯器完成的。堆記憶體分配則都是動態分配,需要我們自己分配記憶體並進行記憶體釋放。
分配效率:棧的分配使用的是機器系統提供的資料結構,在計算機底層有專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執行,效率較高。而堆的分配是由c/c++函式庫提供的,有一定的分配演算法,為了分配成功,會去搜尋可用的足夠大小的空間,還有可能引發使用者態和核心態的切換,效率較低。
從上面介紹的幾個方面可以看出,棧高效,堆靈活,具體如何使用需要根據實際情況而定,不過使用不當的話很有可能引發系統錯誤,下面簡單總結一下常見的情況。
錯誤1:記憶體分配未成功,卻使用了這個分配結果。
正確1: 記憶體分配是有可能失敗的,在使用之前一定要檢查分配結果是否不為null。
錯誤2:記憶體分配成功了,但是沒有進行初始化就使用它。
正確2:記憶體分配成功後,雖然一些簡單資料型別的變數為0,但複雜結構的變數就不確定了,所以一定要進行初始化。
錯誤3:記憶體越界。
正確3:記憶體越界常發生在陣列、容器的使用中,使用前一定要確認其索引/下標有效。
錯誤4:沒有釋放已分配記憶體,造成記憶體洩漏。
正確4:分配了記憶體之後忘記釋放記憶體是可能發生的,造成記憶體洩漏,如果記憶體洩漏嚴重,就會造成記憶體不足或記憶體耗盡,所以malloc/free、new/delete一定要配對使用。
錯誤5:函式返回了指向區域性變數的指標或引用。
正確5:區域性變數使用的是棧記憶體,函式返回時區域性變數的記憶體被自動釋放,這時再通過指標或引用來使用這個變數的話就出錯了,所以返回指向區域性變數的指標或引用是禁止的,如果返回值為指標或引用的話,可以返回靜態變數或全域性變數,或者返回堆上的變數。
錯誤6:誤用野指標。
正確6:用free或delete釋放了記憶體後,還繼續使用這塊記憶體,這是有問題的,在記憶體釋放後一定要把指標設定為null,避免野指標。
當c++類中定義了指標成員變數,使用的卻是預設拷貝建構函式時,是有可能發生常見的double free問題的,具體可參考:
valgrind是乙個記憶體檢測工具,可以用來檢測記憶體非法訪問、記憶體洩漏等問題,具體可參考:
c c 記憶體管理
我一直覺得記憶體是很複雜的東西.也許我把這篇文章完成的時候,我會了解一點c 的記憶體管理機制 從硬體開始 記憶體器位址空間 匯流排位址空間 cpu位址空間 虛擬記憶體位址空間 程式位址空間 邏輯位址空間 程式位址空間對c 程式設計師來說是可見的,其他位址空間我們並不關心 通過列印pointer的值 ...
C C 記憶體管理
1.相同點 失敗 null 2 使用之前都要進行判斷是否為空 3 釋放空間的方式 free 4 返回值 void 可以強制型別轉換 2.不同點 1 malloc 引數 位元組數 功能 負責將空間給出 2 calloc 引數 單個元素位元組數,元素個數 功能 給出空間,且對空間進行初始化為0 若p為n...
C C 記憶體管理
首先來看一下c c 中記憶體的分布 棧區 又稱作堆疊,非靜態區域性變數,函式引數,返回值都是儲存在棧區的,函式棧幀的建立也是在棧區的 一般棧區的大小只有十幾m 資料段 存放靜態資料和全域性資料的。段 存放可執行的 和唯讀常量。了解完記憶體的分布接下來我們來了解記憶體的管理方式 在c語言中記憶體的管理...