用new和malloc開闢記憶體時,記憶體是硬體資源,需要經過核心態,分配好後給使用者態。這個過程很麻煩,浪費時間,效率差。現在就想到了,一次性分配一大塊記憶體空間給應用程式,應用程式對其進行管理,這樣只有在第一次分配的時候經過核心,其他時候都是從應用程式管理的記憶體上取,釋放,這就是記憶體的自主管理機制。
引入兩個概念;
池:資源的集合;池中申請資源,最後返回給池;實現了資源的迴圈利用。
把分配的一大塊記憶體稱為記憶體池:記憶體的集合。
通過什麼辦法進行記憶體池的操作呢?可以使用c++new開闢記憶體,delete釋放記憶體。
new:
delete:
那麼我們可以對new和delete進行過載,原來的new,delete是從系統上開闢,釋放記憶體,通過過載,實現new分配記憶體池上的資源,delete將資源釋放給記憶體池。
過載new,delete關鍵字函式和malloc,free函式原型一樣:
void* operator new(size_t size);
void operator delete(void* ptr);
記憶體池可以通過new,delete來操作,但是如何表示這大塊記憶體,如何實現new分配,delete**的功能?
【1. 記憶體碎片】
在使用系統記憶體資源時,會經常發生記憶體碎片的問題:
內碎片:申請了8位元組,但實際只用5位元組,浪費了3位元組,這就是內碎片。
外碎片:乙個小記憶體塊卡在兩個大記憶體塊之間,無法被分配。
使用系統的new和malloc不僅會導致記憶體使用效率低,還會產生外碎片問題。所以我們有了記憶體池,
讓系統一次性分配大塊記憶體,大記憶體不容易產生記憶體碎,但是我們必須對其進行管理,這樣才知道,下一次從哪個位置分配。所以要對記憶體池進行一定的管理:
選擇乙個合適的資料結構來儲存這一大塊記憶體,並可以進行管理,我們選擇靜態鍊錶。
【2.靜態鍊錶】
靜態鍊錶是以陣列的形式存在,做鍊錶的處理,有:
struct node
靜態鍊錶會犧牲0號下標的空間,作為未分配出去的鍊錶的頭結點。犧牲最後乙個下標的空間,作為已分配出去的頭結點。如下圖所示:
【3. 儲存記憶體池的資料結構】
可以用優化後的靜態鍊錶儲存記憶體池,我們對靜態鍊錶進行一定的優化:
未分配結點:靜態鍊錶需要將0下標犧牲,我們可以定義不帶頭節點的單鏈表,用乙個指標指向這塊記憶體即可。對其進行優化,這樣可以使用的記憶體空間增多。
已分配結點:靜態鍊錶需要通過乙個鍊錶結點進行統一管理。但是在記憶體池中,我們是將記憶體分配給乙個變數使用,如:int* p=new int;記憶體釋放時,釋放p即可。所以不用進行統一的管理,因為有外部變數在管理。
所以記憶體池的資料結構是優化的靜態鍊錶:
以隊列為基礎,實現乙個鏈隊:入隊:new結點;出隊:delete結點;以模板方式是實現。
鏈隊由兩個類構成:結點類,和管理結點類
【(一) 結點類】
成員變數包含資料域,指標域
建構函式,將結點資料放入,指標指向null。
需要申請、釋放結點,成員方法有過載的new,delete函式。表示在結點類中需要對記憶體池進行管理
定義指向記憶體池的靜態指標。需要所有物件都可以看見,所以是靜態的。
【1. 生成乙個結點】
生成node_count大小的記憶體池,從記憶體池中獲取,釋放結點記憶體。
生成的記憶體池如下:
void * operator new(size_t size)//過載關鍵字new,實現記憶體池的開闢,分配一塊記憶體存放結點
pcur->pnext=null;//記憶體池最後乙個結點為null
} void* ptr=pool;
pool=pool->pnext;
return ptr;
}
【2. 刪除乙個結點】把分配的結點**到記憶體池中。
void operator delete(void* ptr)//過載關鍵字delete,將分配的結點插入記憶體池
【(二) 鏈隊類】成員變數:定義隊頭,隊尾指標指向結點。
【1. 建構函式】
建構函式生成乙個結點,此時new呼叫我們過載的new函式,此時獲得的頭節點是鏈隊的頭結點,記憶體池沒有頭結點:
【2. 析構】刪除所有的結點,迴圈刪除,這時的delete呼叫的是自己的寫的。
~queue()//迴圈刪除每個結點,呼叫自己寫的,即將每個結點還給記憶體池
phead=null;
}
【3. 入隊push】
void push(t val)//隊尾入隊
【4. 出隊】
void pop()//隊頭出隊
node* pcur=phead->pnext;
phead->pnext=pcur->pnext;
delete pcur;//這時呼叫的是我們過載的delete,將結點還給記憶體池
}
【5. 獲取隊尾】獲取隊尾指標指向結點的資料即可。
t back()//獲取隊尾元素
return ptail->mdata;
【6. 獲取隊頭】獲取隊頭指標指向結點的資料即可。
t front()//獲取隊頭
return phead->mdata;
}
整合得到完整**,執行結果如下:
實現了鏈隊的記憶體池,每一次分配,釋放結點,都是在分配的一大塊記憶體上獲取的。
加油哦!?。
記憶體池 C 記憶體池
c c 下記憶體管理是讓幾乎每乙個程式設計師頭疼的問題,分配足夠的記憶體 追蹤記憶體的分配 在不需要的時候釋放記憶體 這個任務相當複雜。1.呼叫malloc new,系統需要根據 最先匹配 最優匹配 或其他演算法在記憶體空閒塊表中查詢一塊空閒記憶體,呼叫free delete,系統可能需要合併空閒記...
記憶體池 簡單的記憶體池的實現
當頻繁地用malloc申請記憶體,然後再用free釋放記憶體時,會存在兩個主要問題。第乙個問題是頻繁的分配釋放記憶體可能導致系統記憶體碎片過多 第二個問題是分配釋放記憶體花費的時間可能比較多 這個問題不太明顯 這個時候我們就可以考慮使用記憶體池了。最樸素的記憶體池思想就是,首先你向系統申請一塊很大的...
C 記憶體池的實現
file memorypool.h note hangzhou hikvision system technology co.ltd.all right reserved.brief windows下記憶體池的實現 author zhangpeng nj 163.com date 11 15 201...