簡單說下:設計記憶體池的目的主要是為了解決在一些特殊的場合(比如:網路程式設計時接受資料報)頻繁的建立和銷毀、造成的大量的記憶體碎片和降低效率。
在stl的記憶體池中可以看到、它的實現是利用了乙個自由鍊錶陣列、obj** free_lists;陣列中每個元素都是乙個自由鍊錶的頭指標、它指向乙個由多個記憶體塊連成的鍊錶。另外、每個鍊錶中所包含的記憶體塊的大小是固定的、stl中是從8開始到128byte結束、塊與塊間的大小間隔也是8、也就是8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128。那麼free_lists鍊錶陣列的大小也就是16。
先看一下我按照stl中的方案實現的記憶體池**:
//標頭檔案
#pragma once
#include #include #include using namespace std;
class cmemorypool
; obj** freelists;
char* startpos;
char* endpos;
unsigned int heapsize; //記憶體池分配的總大小
char** ptrtoheadeachalloc; //每次記憶體池向系統申請空間時這裡會記錄乙個首位址
size_t maxalloctime; //最大次數、用於記錄
size_t alloctime; //向系統申請空間的次數
public:
cmemorypool(unsigned nalign = 8,unsigned nmaxbytes = 128,unsigned nnumberofaddnodeeachtime = 20);
virtual ~cmemorypool(void);
private:
size_t round_up(size_t size)
size_t freelist_index(size_t size)
protected:
void* allocate(size_t size);
void* refill(size_t size);
char* blockalloc(size_t size, size_t& num);
void deallocate(void* ptr, size_t size);
void close();
};
//原始檔
#include "memorypool.h"
cmemorypool::cmemorypool(unsigned nalign,unsigned nmaxbytes ,unsigned nnumberofaddnodeeachtime)
:align(nalign),maxbytes(round_up(nmaxbytes)),numberoffreelist(nmaxbytes / nalign),
numberofaddnodeeachtime(nnumberofaddnodeeachtime),
freelists(new obj*[numberoffreelist]),startpos(null),endpos(null),heapsize(0),
ptrtoheadeachalloc((char**)malloc(50)),maxalloctime(50),alloctime(0)
cmemorypool::~cmemorypool(void)
void cmemorypool::close()
} if(ptrtoheadeachalloc)
if(freelists)
}//分配指定大小記憶體
void* cmemorypool::allocate(size_t size)
size_t index = freelist_index(size);
obj* node = freelists[index];
if(node)
return refill(round_up(size));
}//填充乙個自由鍊錶、返回頭
void* cmemorypool::refill(size_t size)
elseelse
} return block; }}
//分配記憶體塊
char* cmemorypool::blockalloc(size_t size, size_t& num)
else if(totalsize >= size)else
startpos = (char*)malloc(allocsize);
if(startpos == null)
}//執行到這、說明記憶體分配失敗且沒有足夠大的空閒節點
throw bad_alloc();
}else
maxalloctime += 50;
}ptrtoheadeachalloc[alloctime++] = startpos;
heapsize += allocsize;
endpos = startpos + allocsize;
return blockalloc(size,num);
} }}//釋放記憶體
void cmemorypool::deallocate(void* ptr, size_t size)
else
}
簡述一下它的實現步驟:
1、最開始的時候因為不知道要分配多大的空間、所以這是startpos - endpos為0、也就是記憶體池是空的。在分配時先到對應的free_list(申請空間與塊大小最接近的鍊錶)中尋找、是否有空間、如果沒有再去記憶體池中尋找、然而這時記憶體池中也沒有空間、那麼就只能向系統申請空間了。如果成功:則進行相應的記憶體分配、並且將剩餘部分記憶體(有一部分記憶體池自己留下了)分塊「掛」在對應的free_list上。
2、如果在記憶體池向系統申請空間時失敗了、那麼為了「應急」就查詢塊大小比使用者所申請的空間還大的鍊錶中是否存在節點塊、如果存在直接將它「拿下來」放到記憶體池中(也就是調整startpos和endpos)、再重新分配(這時記憶體池中已經有了空間所以就可以直接將它提供給使用者了)。
有幾點需要注意:
1、為什麼obj節點要使用共用體?
其意思就是:
struct obj
;union obj
;
這裡再說下:柔性陣列
struct node
;
這時node的大小是4byte、因為b陣列0長度。但是b陣列的位址在node位址的下面也就是:
node* n = (node*)malloc(sizeof(node) + 4); 這時連續多出來的4個位元組的首位址就是b、還有:
char str[100];
node* p = (node*)str;字串的前4個位元組被a占用、後面的都被b所使用。
結構體柔性陣列的位址是在整個node之後的、但是共用體柔性陣列的位址就是node的首位址、柔性陣列可表示可變長度的空間、所以上面obj中的data就是為了適應不同的塊大小。因為它可以表示可變長度。
2、塊大小必須大於或等於乙個指標的大小、也就是align大於等於4。
那是因為每個節點其實就是分配的記憶體塊的頭部分的4個位元組、如果記憶體塊本身不能大於4那麼也就不夠將空間轉換為obj。
下面是根據記憶體池實現的分配器:
#pragma once
#include #include "memorypool.h"
/*模板不支援分離編譯*/
templateclass cmyallocator : public cmemorypool
;templatecmyallocator::cmyallocator(unsigned nalign,unsigned nmaxbytes,unsigned nnumberofaddnodeeachtime)
:cmemorypool(nalign,nmaxbytes,nnumberofaddnodeeachtime)
templatecmyallocator::~cmyallocator(void)
templatet* cmyallocator::allocate()
templatet* cmyallocator::allocate(size_type numoft)
templatevoid cmyallocator::deallocate(t* ptr)
templatevoid cmyallocator::deallocate(t* ptr,size_type num)
templatevoid cmyallocator::construct(t* ptr)
templatevoid cmyallocator::construct(t* ptr,const t& value)
templatevoid cmyallocator::destroy(t* ptr)
templatevoid cmyallocator::destroy(t* first,t* last)
}templatevoid cmyallocator::close()
stl記憶體池學習(二) 走近記憶體池
這一節學習基礎知識 所用到的資料結構。首先看記憶體池的介面 code ifndef mem pool h define mem pool h static size t freelist index size t bytes static size t round up size t bytes s...
stl記憶體池學習(一) 記憶體池初認識
序號 0123 4567 891011 1213 1415 串接區塊816 2432 4048 5664 7280 8896 104112 120128 範圍1 8 9 16 17 24 25 32 33 40 41 48 49 56 57 64 65 72 73 80 81 88 89 96 97...
stl記憶體池學習(一) 記憶體池初認識
序號 0123 4567 891011 1213 1415 串接區塊816 2432 4048 5664 7280 8896 104112 120128 範圍1 8 9 16 17 24 25 32 33 40 41 48 49 56 57 64 65 72 73 80 81 88 89 96 97...