- 書上的內(nèi)容基本上在下面的代碼討論了,但是并沒有完全按照書上實現(xiàn)
#include <cassert>
#include <vector>
#include <map>
using std::vector;
using std::map;
/*
管理相同自定義大小的內(nèi)存塊,可以使用的內(nèi)存總數(shù)的限制在于:
1.系統(tǒng)(安裝的內(nèi)存大小)
2.程序類型(32位、64位)
*/
class CFixedAllocator
{
public:
CFixedAllocator(const size_t nBlockSizeC,
const unsigned char nBlockCountC) : nBlockSize_(nBlockSizeC),
nBlockCount_(nBlockCountC), pAlloc_(nullptr), pDealloc_(nullptr)
{
assert(nBlockCountC);
}
private:
//管理相同自定義大小的內(nèi)存塊,內(nèi)存塊總數(shù)不超過255個
struct SChunkMemory
{
const bool Init(const size_t nBlockSizeC,
const unsigned char nBlockCountC);
void Release();
void* Allocate(const size_t nBlockSizeC);
void Deallocate(void* pValue, const size_t nBlockSizeC);
unsigned char* pData_; //分配的內(nèi)存
unsigned char nFirstAvailableBlock_; //第一個可用的區(qū)塊索引
unsigned char nBlockAvailableCount_; //可用區(qū)塊總數(shù)
/*
這里的索引與總數(shù)都是單字節(jié)類型是為了兼容只分配一個字節(jié)的情況
*/
};
private:
size_t nBlockSize_;
unsigned char nBlockCount_;
vector<SChunkMemory> vecChunkMemory_;
SChunkMemory* pAlloc_;
SChunkMemory* pDealloc_;
/*
為了提高查找速度,面對每一次分配,并非遍歷整個vecChunkMemory_來尋找空間,
而是保存一個指針,指向最近一次分配所使用的SChunkMemory,若其不存在可用空間,
才會引發(fā)一次線性查找
*/
public:
void* Allocate();
const bool Deallocate(void* pValue);
const size_t GetBlockSize() const { return nBlockSize_; }
void Release();
};
const bool CFixedAllocator::SChunkMemory::Init(const size_t nBlockSizeC,
const unsigned char nBlockCountC)
{
pData_ = new (std::nothrow) unsigned char[nBlockSizeC * nBlockCountC];
if (!pData_)
{
return false;
}
nFirstAvailableBlock_ = 0;
nBlockAvailableCount_ = nBlockCountC;
unsigned char* pTem = pData_;
for (int i = 0; i < nBlockCountC; pTem += nBlockSizeC)
{
*pTem = ++i;
/*
拿未被使用的區(qū)塊的第一個字節(jié)來放置下一個未被使用的區(qū)塊的索引,
這樣就有了一個由可用區(qū)塊組成的單向鏈表,且無需占用額外內(nèi)存
*/
}
return true;
}
void CFixedAllocator::SChunkMemory::Release()
{
if (pData_)
{
delete[] pData_;
}
nBlockAvailableCount_ = 0;
}
void* CFixedAllocator::SChunkMemory::Allocate(const size_t nBlockSizeC)
{
if (!nBlockAvailableCount_)
{
return nullptr;
}
unsigned char* pResult = pData_ + nFirstAvailableBlock_ * nBlockSizeC;
nFirstAvailableBlock_ = *pResult;
--nBlockAvailableCount_;
return pResult;
}
void CFixedAllocator::SChunkMemory::Deallocate(void* pValue,
const size_t nBlockSizeC)
{
unsigned char* pRelease = static_cast<unsigned char*>(pValue);
assert(pValue >= pData_);
assert(!((pRelease - pData_) % nBlockSizeC));
//指明下一個可用內(nèi)存塊Id,道理其實和Init里是一置的
*pRelease = nFirstAvailableBlock_;
nFirstAvailableBlock_ =
static_cast<unsigned char>((pRelease - pData_) / nBlockSizeC);
assert(nFirstAvailableBlock_ == (pRelease - pData_) / nBlockSizeC);
++nBlockAvailableCount_;
}
void* CFixedAllocator::Allocate()
{
if (!pAlloc_ || !pAlloc_->nBlockAvailableCount_)
{
for (auto it = vecChunkMemory_.begin(); ; ++it)
{
if (vecChunkMemory_.end() == it)
{
vecChunkMemory_.emplace_back(SChunkMemory());
if (!vecChunkMemory_.back().Init(nBlockSize_,
nBlockCount_))
{
return nullptr;
}
pAlloc_ = &vecChunkMemory_.back();
pDealloc_ = &vecChunkMemory_.front();
break;
}
else if (it->nBlockAvailableCount_)
{
pAlloc_ = &*it;
break;
}
}
}
return pAlloc_->Allocate(nBlockSize_);
}
const bool CFixedAllocator::Deallocate(void* pValue)
{
/*
策略一:可以專門建立一個vector來保存歸還的內(nèi)存塊,當客戶進行內(nèi)存歸還的時候,
就將此內(nèi)存添加到vector中,用戶再申請的時候就直接從這個vector中取。
以上這個策略在用戶隨機分配和歸還時候效果好,但是在用戶批量分配和批量釋放時候,
效果很差,因為其需要維護一個額外的vector
策略二:建立一個指針指向上次進行歸還的那個SChunkMemory對象,
如果被歸還的指針不屬于這個對象,則進行線性查找
*/
if (pValue >= pDealloc_->pData_ &&
pValue <= pDealloc_->pData_ + nBlockSize_ * nBlockCount_)
{
pDealloc_->Deallocate(pValue, nBlockSize_);
return true;
}
for (auto it = vecChunkMemory_.begin(); it != vecChunkMemory_.end();
++it)
{
if (pValue >= it->pData_ &&
pValue <= it->pData_ + nBlockSize_ * nBlockCount_)
{
it->Deallocate(pValue, nBlockSize_);
return true;
}
}
return false;
}
void CFixedAllocator::Release()
{
for (auto it = vecChunkMemory_.begin();
it != vecChunkMemory_.end(); ++it)
{
it->Release();
}
vecChunkMemory_.clear();
}
//自己編的 其分配的內(nèi)存大小可以自定義
class CSmallObjAllocator
{
public:
CSmallObjAllocator(const unsigned char nBlockCountC = 255) :
nBlockCountC_(nBlockCountC) {}
public:
void* Allocate(const size_t nMemorySizeC);
const bool Deallocate(void* pValue, const size_t nMemorySizeC);
void Release();
private:
map<size_t, CFixedAllocator> mapFixAllocator_;
const unsigned nBlockCountC_;
};
void* CSmallObjAllocator::Allocate(const size_t nMemorySizeC)
{
auto it = mapFixAllocator_.find(nMemorySizeC);
if (it != mapFixAllocator_.end())
{
return it->second.Allocate();
}
mapFixAllocator_.emplace(std::make_pair(nMemorySizeC,
CFixedAllocator(nMemorySizeC, nBlockCountC_)));
return mapFixAllocator_.at(nMemorySizeC).Allocate();
}
const bool CSmallObjAllocator::Deallocate(void* pValue,
const size_t nMemorySizeC)
{
auto it = mapFixAllocator_.find(nMemorySizeC);
if (it == mapFixAllocator_.end())
{
return false;
}
return it->second.Deallocate(pValue);
}
void CSmallObjAllocator::Release()
{
for (auto it = mapFixAllocator_.begin();
it != mapFixAllocator_.end(); ++it)
{
it->second.Release();
}
mapFixAllocator_.clear();
}
int main()
{
CSmallObjAllocator SmallObj;
void* aPValue[] =
{
SmallObj.Allocate(10),
SmallObj.Allocate(10),
SmallObj.Allocate(1),
SmallObj.Allocate(2),
SmallObj.Allocate(5)
};
SmallObj.Deallocate(aPValue[0], 10);
SmallObj.Deallocate(aPValue[1], 10);
SmallObj.Deallocate(aPValue[2], 1);
SmallObj.Deallocate(aPValue[3], 2);
SmallObj.Deallocate(aPValue[4], 5);
return 0;
}
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。