話說(shuō)一直想找一個(gè)別人寫(xiě)好的使用,可惜沒(méi)什么人會(huì)拿這小東西發(fā)布,只好自寫(xiě)一個(gè)。
1.多級(jí)鏈表分配池
我不知道這種設(shè)計(jì)的具體學(xué)名是什么,這部分的內(nèi)容也許你去看《STL源碼分析》的有關(guān)章節(jié)更合適一些,這里我只能用我粗陋的語(yǔ)言描述一下。
內(nèi)存池,完全可以從字面上理解為從池子里申請(qǐng)內(nèi)存,釋放的時(shí)候還給池子。
最簡(jiǎn)單的內(nèi)存池應(yīng)該是fix_pool吧,即每次分配出來(lái)的內(nèi)存塊大小是固定的。這種池子的管理結(jié)構(gòu)是一個(gè)鏈表,鏈表的每一個(gè)節(jié)點(diǎn)為固定大小的內(nèi)存塊。分配的時(shí)候,直接返回鏈表的第一個(gè)節(jié)點(diǎn),節(jié)點(diǎn)不足時(shí),從系統(tǒng)申請(qǐng)大塊內(nèi)存分成多個(gè)節(jié)點(diǎn)加入鏈表;釋放的時(shí)候更簡(jiǎn)單,將釋放的內(nèi)存加入鏈表頭。
假設(shè)fix_pool的fix size = 128,那么內(nèi)存池可以為128byte以下的任意大小的請(qǐng)求進(jìn)行分配,但是這樣做相當(dāng)浪費(fèi)呢,于是unfix_pool就在此基礎(chǔ)上出現(xiàn)了。
由多個(gè)分配大小不同的fix_pool所組成的內(nèi)存池就叫做多級(jí)鏈表分配池,我是這么定義的。
常規(guī)上會(huì)定義8,16,24,32,...,112,120,128這些分配大小,共16級(jí)。分配或者釋放的時(shí)候,判斷請(qǐng)求的大小在哪一級(jí)別上,用該級(jí)別的fix_pool鏈表進(jìn)行分配或者釋放。
2.泄漏檢測(cè)
當(dāng)所有的分配都經(jīng)過(guò)你的手的時(shí)候,泄漏檢測(cè)什么的再簡(jiǎn)單不過(guò)了。
找個(gè)地方把分配的東西記錄下來(lái),釋放的時(shí)候把記錄去掉。程序退出的時(shí)候還存在的分配記錄就是泄漏了。
我個(gè)人選用的方法是給每一個(gè)分配請(qǐng)求多分配一些內(nèi)存,用來(lái)記錄分配的信息,并將這部分信息用雙向鏈表串起來(lái)。釋放的時(shí)候?qū)︶尫诺闹羔樧鲆幌轮羔樒凭涂梢哉业叫畔⒂涗洸⒁瞥鲭p向鏈表。
這個(gè)方法的開(kāi)銷是常數(shù)級(jí)的,不過(guò)無(wú)法處理重復(fù)刪除的問(wèn)題。
3.operater new
要把你的內(nèi)存池應(yīng)用到每一個(gè)角落,需要定義operator new和operator delete。
對(duì)于placement new而言,operator new[]和operator delete[]是必須的,無(wú)法省略。
4.線程安全
我沒(méi)聽(tīng)說(shuō)過(guò)new/delete,malloc/free是線程不安全的,所以在內(nèi)存池的allocate/deallocate接口處直接加了鎖。
想降低開(kāi)銷的同學(xué)可以使用spin lock,而不是mutex。
1.多級(jí)鏈表分配池
我不知道這種設(shè)計(jì)的具體學(xué)名是什么,這部分的內(nèi)容也許你去看《STL源碼分析》的有關(guān)章節(jié)更合適一些,這里我只能用我粗陋的語(yǔ)言描述一下。
內(nèi)存池,完全可以從字面上理解為從池子里申請(qǐng)內(nèi)存,釋放的時(shí)候還給池子。
最簡(jiǎn)單的內(nèi)存池應(yīng)該是fix_pool吧,即每次分配出來(lái)的內(nèi)存塊大小是固定的。這種池子的管理結(jié)構(gòu)是一個(gè)鏈表,鏈表的每一個(gè)節(jié)點(diǎn)為固定大小的內(nèi)存塊。分配的時(shí)候,直接返回鏈表的第一個(gè)節(jié)點(diǎn),節(jié)點(diǎn)不足時(shí),從系統(tǒng)申請(qǐng)大塊內(nèi)存分成多個(gè)節(jié)點(diǎn)加入鏈表;釋放的時(shí)候更簡(jiǎn)單,將釋放的內(nèi)存加入鏈表頭。
假設(shè)fix_pool的fix size = 128,那么內(nèi)存池可以為128byte以下的任意大小的請(qǐng)求進(jìn)行分配,但是這樣做相當(dāng)浪費(fèi)呢,于是unfix_pool就在此基礎(chǔ)上出現(xiàn)了。
由多個(gè)分配大小不同的fix_pool所組成的內(nèi)存池就叫做多級(jí)鏈表分配池,我是這么定義的。
常規(guī)上會(huì)定義8,16,24,32,...,112,120,128這些分配大小,共16級(jí)。分配或者釋放的時(shí)候,判斷請(qǐng)求的大小在哪一級(jí)別上,用該級(jí)別的fix_pool鏈表進(jìn)行分配或者釋放。
2.泄漏檢測(cè)
當(dāng)所有的分配都經(jīng)過(guò)你的手的時(shí)候,泄漏檢測(cè)什么的再簡(jiǎn)單不過(guò)了。
找個(gè)地方把分配的東西記錄下來(lái),釋放的時(shí)候把記錄去掉。程序退出的時(shí)候還存在的分配記錄就是泄漏了。
我個(gè)人選用的方法是給每一個(gè)分配請(qǐng)求多分配一些內(nèi)存,用來(lái)記錄分配的信息,并將這部分信息用雙向鏈表串起來(lái)。釋放的時(shí)候?qū)︶尫诺闹羔樧鲆幌轮羔樒凭涂梢哉业叫畔⒂涗洸⒁瞥鲭p向鏈表。
這個(gè)方法的開(kāi)銷是常數(shù)級(jí)的,不過(guò)無(wú)法處理重復(fù)刪除的問(wèn)題。
3.operater new
要把你的內(nèi)存池應(yīng)用到每一個(gè)角落,需要定義operator new和operator delete。
void* operator new(size_t) throw(std::bad_alloc);
void operator delete(void* p);
但是這還不夠,誰(shuí)也不想看到一堆泄漏信息而找不到泄漏的位置,因此還需要定義帶附加參數(shù)的operator。void operator delete(void* p);
對(duì)于placement new而言,operator new[]和operator delete[]是必須的,無(wú)法省略。
void* operator new(size_t, const char* file, int line, const char* function);
void* operator new[](size_t, const char*, int, const char*);
void operator delete(void* p);
void operator delete[](void* p);
為了能用上新的operator,需要在頭文件中重新定義new,并包含進(jìn)每一個(gè)cpp文件。void* operator new[](size_t, const char*, int, const char*);
void operator delete(void* p);
void operator delete[](void* p);
//op_new.h
#define DEBUG_NEW new(__FILE__, __LINE__, __FUNCTION__)
#define new DEBUG_new
不過(guò)重定義new會(huì)和自行使用placement new的地方?jīng)_突,如stl容器庫(kù),這時(shí)候要undef new后才能編譯沖突組件。#define DEBUG_NEW new(__FILE__, __LINE__, __FUNCTION__)
#define new DEBUG_new
#undef new
#include <vector>
#include "op_new.h"
#include <vector>
#include "op_new.h"
4.線程安全
我沒(méi)聽(tīng)說(shuō)過(guò)new/delete,malloc/free是線程不安全的,所以在內(nèi)存池的allocate/deallocate接口處直接加了鎖。
想降低開(kāi)銷的同學(xué)可以使用spin lock,而不是mutex。