游戲中的內(nèi)存管理,也可以叫做內(nèi)存池,好像有些也叫對象池,其實方法不少。我就講哈我自己做的點點經(jīng)驗和想法。
對應(yīng)不同的類,使用模板類是肯定的。有些類可能不需要自動調(diào)用構(gòu)造和析構(gòu),內(nèi)存分配器就分出來了,就只負責(zé)分配對象的內(nèi)存。方便起見,還是要有new和delete功能的對應(yīng)方法,那就另外用一個模板類包裝內(nèi)存分配器,是外部使用的類,New函數(shù)取得對象內(nèi)存后再調(diào)用構(gòu)造函數(shù),也要有malloc和free直接調(diào)用內(nèi)存分配器的對應(yīng)函數(shù)。
內(nèi)存到底預(yù)分配多大?其實不好說,但是也是可預(yù)測的,實際測試統(tǒng)計之后還是會找到一個比較可靠的值。其實內(nèi)存不必一次就分配那么多,雖然最大峰值是MAX,大部分時間使用量都是遠小于MAX的。內(nèi)存按組分配要好些,MAX分成多個組,先分配一個組用到,不夠了用完的時候,再要一個組,這樣子使用率要高些。組在完全沒有使用的情況下是可以被回收的,是否要被回收可以變動。這也不會降低好多效率,組的數(shù)量不會很多,而且應(yīng)該更加內(nèi)存使用的情況而定,一個組里面包含多少個對象也是可調(diào)節(jié)的,測試后會有一個較好的值。
大概說哈結(jié)構(gòu)嘛,內(nèi)存分配器(allocator)有malloc和free,組(memorygroup)的單向鏈表,也可以用雙向鏈表我是為了節(jié)約些內(nèi)存。通過模板參數(shù)把類型(T)、組數(shù)(groupsize)、對象數(shù)(objectsize)傳給組。
下面有簡易代碼說明:
1 template<typename T,int gs,int os>
2 class Allocator
3 {
4 T * malloc();
5 void free(void * p);
6
7 MemoryGroup * grouplist;
8 };
組是內(nèi)存分配器的內(nèi)部類,組才真正調(diào)用系統(tǒng)malloc分配整塊內(nèi)存,按類數(shù)分給對象內(nèi)存(memoryobject)數(shù)組分別保存地址。
1 struct MemoryObject
2 {
3 T * p;
4 MemoryObject * next;
5 };
6 struct MemoryGroup
7 {
8 MemoryObject * freelist;
9 MemoryObject objlist[cs];
10 MemoryGroup * next;
11 };
組維護一個空閑對象內(nèi)存鏈表也是單向鏈表,當內(nèi)存分配器需要地址的時候,組就把空閑鏈表中的一個對象內(nèi)存返回,并把它從鏈表中刪除。當內(nèi)存分配器要釋放對象的時候,對象指針傳遞給組,組進行效驗是否由該組分配,如果是就簡單的找到對應(yīng)對象內(nèi)存,添加到空閑鏈表。
外部使用的內(nèi)存管理類包裝內(nèi)存分配器,實現(xiàn)了malloc和free直接調(diào)用內(nèi)存分配器的,還有new和delete函數(shù)是在取得地址后調(diào)用構(gòu)造和調(diào)用析構(gòu)后再傳遞指針。為了安全起見,用特例化把new和delete與malloc和free分離開,一個實例化的模板類只能調(diào)用其中一對函數(shù)。
1 template<class T,int gs,int cs,bool nc,bool ar>
2 class MemoryManager
3 {
4 T * malloc();
5 void free(void * p);
6 };
7
8 template<class T,int gs,int cs,bool nc,bool ar>
9 class MemoryManager<T,gs,cs,true,ar>
10 {
11 T * new();
12 void delete(void * p);
13 };
模板參數(shù)的第4個參數(shù)(needconstruct)選擇使用哪一對函數(shù),第5個參數(shù)(autorecycle)決定要不要在組完全未使用時回收組。當然回收組是可以動態(tài)改變的一個選擇,所以第5個參數(shù)可以通過函數(shù)參數(shù)傳入。回收組可以在內(nèi)存分配器是否對象時檢測組的使用情況,為了跟蹤使用情況可以在組內(nèi)部附加一個計數(shù)器統(tǒng)計未使用對象數(shù)量,初始是設(shè)定的對象數(shù),使用時減1回收時加1,這個計數(shù)器在以后還可以計數(shù)使用率等,作為調(diào)試和測試信息輸出。
為了使用的安全起見,用宏釋放對象指針同時把對象指針賦值為0,因為使用了內(nèi)存管理器所以與一般的釋放宏不同需要傳入內(nèi)存管理。
1 #define FREE(m,p) { if (p) { m.free(p); p=0; } }
2 #define DELETE(m,p) { if (p) { m.delete(p); p=0; } }
基本上就是這么多啦,其實也不是黑復(fù)雜的東西。
后面講哈內(nèi)存使用的不同情況,組數(shù)量和對象數(shù)量設(shè)定的一點想法。