C 基礎 記憶體管理篇

2021-10-07 06:15:41 字數 3999 閱讀 5127

記憶體管理是計算機程式設計最為基本的領域之一。在很多指令碼語言中,您不必擔心記憶體是如何管理的,這並不能使得記憶體管理的重要性有一點點降低。對實際程式設計來說,理解您的記憶體管理器的能力與 侷限性至關重要。在大部分系統語言中,比如 c 和 c++,您必須進行記憶體管理。本文將介紹手工的、 半手工的以及自動的記憶體管理實踐的基本概念。

ibm 記憶體管理介紹

第一級配置器

第一級配置器以 malloc(),free(),realloc()等c函式執行實際的記憶體配置、釋放、重新配置等操作,並且能在記憶體需求不被滿足的時候,呼叫乙個指定的函式

第二級配置器

第二級配置器維護著16個空閒鍊錶(free list),各自管理大小分別為8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytes的小記憶體塊。

如果要分配的記憶體大於 128bytes,則移交給第一級配置器處理,直接用malloc。

如果要分配的記憶體小於 128bytes,則以記憶體池管理(memory pool),使用第二級配置器,找出適合的空閒鍊錶, 從其上摘下乙個節點將其頭指標返回給使用者,這就完成了對使用者的記憶體分配。

釋放過程則正好與分配相對應,如果使用者分配的記憶體大於128bytes,直接用free,否則找出適當的空閒鍊錶, 將指標所指的該段記憶體重新連線到空閒鍊錶中(注意此時並不把記憶體返回給作業系統, 如此可以重複利用)。

小記憶體塊(空閒鍊錶管理)–> 大記憶體塊(malloc 向os申請)

流程總結

使用 allocate 請求size大小的記憶體空間, 如果需要請求的記憶體大小大於128bytes, 直接使用malloc.

如果需要的記憶體大小小於128bytes, allocate根據size找到最適合的空閒鍊錶.

a. 如果鍊錶不為空, 返回第乙個記憶體塊, 煉表頭改為第二個記憶體塊。

b. 如果鍊錶為空, 使用refill為該空閒鍊錶填充新的空間。

x. 如果記憶體池中有大於乙個記憶體塊的空間, 分配盡可能多的記憶體塊(但是最多20個), 將乙個記憶體塊返回, 其他的記憶體塊新增到鍊錶中。

y. 如果記憶體池只有乙個記憶體塊的空間, 直接返回給使用者.

z. 如果記憶體池連乙個記憶體塊的空間都沒有, 再次向作業系統請求分配記憶體.

i 系統記憶體足夠,分配成功,再次進行b過程

ii 分配失敗, 迴圈各個空閒鍊錶, 尋找空間

a. 找到空間, 再次進行過程b

b. 找不到空間, 丟擲異常

使用者呼叫deallocate釋放記憶體空間, 如果要求釋放的記憶體空間大於128bytes, 直接呼叫free。

否則按照其大小找到合適的空閒鍊錶, 並將其插入。

特點其實是這樣的:

剛開始初始化記憶體池的時候, 其實記憶體池中並沒有記憶體, 同時所有的空閒鍊錶都為空鍊錶.

只有使用者第一次向記憶體池請求記憶體時, 記憶體池會依次執行上述過程的 1->2->b->z來完成記憶體池以及鍊錶的首次填充, 而此時, 其他未使用鍊錶仍然是空的

malloc的全稱是memory allocation,中文叫做:動態記憶體分配。

原型:extern void* malloc(unsigned int num_bytes);

說明:分配長度為num_bytes位元組的記憶體塊。如果分配成功,則返回指向被分類記憶體的指標;如果分配失敗,則返回空指標null。(所以申請完記憶體需要判斷所申請記憶體是否為空)當記憶體不再使用時,應使用free()函式講記憶體塊釋放。

返回型別:void型別,表示通用變體型別指標,c,c++規定,void型別可以強制轉換為任何其他型別的指標;void*指申請記憶體空間時,還不知道使用者用這段空間來儲存什麼型別的資料。

釋放:void free(void * firstbyte);講malloc分配的空間還給程式或者是作業系統,也就是釋放了這塊記憶體。

注意事項:

1)申請記憶體空間後,必須檢查是否分配成功;

2)當不需要再使用申請的記憶體時,記得釋放;釋放後應該把指向這塊記憶體的指標指向null,以防後面的程式不小心使用了野指標

3)malloc和free應該配對使用;釋放只能釋放一次,若釋放兩次或更多會出現錯誤,(釋放空指標例外,釋放空指標其實等於啥都沒做,釋放空指標多少次都沒有問題)

4)malloc從堆裡面獲得記憶體;函式返回的指標指向堆裡面的一塊記憶體。作業系統中有乙個記錄空閒記憶體位址的鍊錶,當作業系統收到程式的申請時,就會遍歷鍊錶,然後尋找第乙個空間大於所申請空間的堆結點,然後將該結點從空閒結點鍊錶中刪除,並將該結點分配給程式。

c++中,用new和delete動態建立和釋放陣列或者單個物件。

動態建立物件時,只需要指定其資料型別,而不必為該物件命名。

delete pi;//釋放單個物件

delete [ ] pi;//釋放陣列

new 和 malloc 細微區別

申請的記憶體所在位置

new操作符從自由儲存區(free store)上為物件動態分配記憶體空間,而malloc函式從堆上動態分配記憶體。自由儲存區是c++基於new操作符的乙個抽象概念,凡是通過new操作符進行記憶體申請,該記憶體即為自由儲存區。而堆是作業系統中的術語,是作業系統所維護的一塊特殊記憶體,用於程式的記憶體動態分配,c語言使用malloc從堆上分配記憶體,使用free釋放已分配的對應記憶體。

那麼自由儲存區是否能夠是堆(問題等價於new是否能在堆上動態分配記憶體),這取決於operator new 的實現細節。自由儲存區不僅可以是堆,還可以是靜態儲存區,這都看operator new在**為物件分配記憶體。

特別的,new甚至可以不為物件分配記憶體!

返回型別安全性

new操作符記憶體分配成功時,返回的是物件型別的指標,型別嚴格與物件匹配,無須進行型別轉換,故new是符合型別安全性的操作符。而malloc記憶體分配成功則是返回void * ,需要通過強制型別轉換將void*指標轉換成我們需要的型別。

型別安全很大程度上可以等價於記憶體安全,型別安全的**不會試圖方法自己沒被授權的記憶體區域。關於c++的型別安全性可說的又有很多了。

記憶體分配失敗時候的返回值

new記憶體分配失敗時,會丟擲bac_alloc異常,它不會返回null;malloc分配記憶體失敗時返回null。

智慧型指標模板

template

<

typename t>

class

smart_ptrs

;template

<

typename t>

smart_ptrs

::smart_ptrs

(t *p)

:count

(new

int(1)

),p(p)

//指標運算子

template

<

typename t>

t* smart_ptrs

::operator

->()

// 解引用

template

<

typename t>

t& smart_ptrs

::operator*(

)//析構函式

template

<

typename t>

smart_ptrs::~

smart_ptrs()

}//賦值運算子

template

<

typename t>

smart_ptrs

& smart_ptrs

::operator

=(smart_ptrs& sp)

this

->p = sp.p;

this

->count = sp.count;

return

*this

;}

基礎篇 記憶體管理

記憶體問題主要是兩方面 記憶體溢位,野指標異常.記憶體溢位 ios給每個應用程式一定的記憶體用於程式執行,一旦超出記憶體上線,程式就會crash 野指標 記憶體空間已經被系統收回仍舊在只用這塊記憶體,程式就會crash 記憶體管理方式 mrc,arc mrc的記憶體管理機制是引用計數 arc是基於m...

學習篇 C 基礎 記憶體分割槽

二 程式執行後 三 new操作符 四 一些tips 程式在執行時,將記憶體大方向劃分為4個區域 區 存放 函式體的二進位制 由作業系統進行管理 全域性區 存放 全域性變數和 靜態變數以及 常量棧區 由 編譯器自動分配釋放,存放函式的引數值 區域性變數等 堆區 由 程式設計師分配和釋放,若程式設計師不...

c基礎之記憶體管理

一 作用域 全域性變數和區域性變數 靜態全域性和區域性變數 總結 型別作用域 生命週期 區域性變數 int a 10 從變數定義到函式結束 區域性變數建立到函式結束 全域性變數 int a 10 整個專案檔案 程式建立到程式結束 static 區域性變數 int a 10 從變數定義到函式結束 程式...