第四章(小型对象分配技术:smart-object allocation)
来源:互联网 发布:淘宝美工店铺装修教程 编辑:程序博客网 时间:2024/06/05 21:12
分配原理
block:最小单位,外部指定,一般每个block从4~64byte不等。我们称为blocksize
chunk:包含多个block。个数我们称为blocknum。每个chunk大小为blocknum*blocksize。一般为固定,大小我们称为page
fixedAllocator:包含多个chunk。里面的chunk的block大小都是固定的。即每个fixedAllocator包含的是一种类型的chunk.
smartObjectAlllocator:包含多个fixedAllocator。固定个数,根据外部初始化的时候指定。
smartObject:外部使用的类。
举个例子就明白了。如smartObject初始化一个page为4096byte。最小的block为4,最大的为64,每次增长4个byte。这些值都是初始化可以设定改变的
那么smartObjectAllocator包含的fixedAllocator依次为:4*1, 4*2, 4*3....4*16大小的blocksize的chunk。有16个不同类型的fiexdAllocator
第一个fixAllocator中包含的Chunk的类型是:每个block为4byte。包含的block的个数定义为unsigned char类型,不超过255,包含255个block
最后一个fixAllocator中包含的chunk的信息室:每个block的大小是64bte,个数是4096/64=64。即包含64个连续的block
如果用户需要分配16byte类型的内存,则从里面找到最合适的Chunk,然后分配给它。fixedAllocator默认是不包含任何Chunk的,如果需要使用,则new一个出来。
代码实现
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Chunk.h
/** @file Chunk.h
* @note HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* @brief 一个内存分配器中,单个Chunk的大小是固定的,为blocksize * numblocks
然后每个Chunk的分配方式是不同的。如单个blocksize大小为16,则numblocks的大小就为pagesize/16
* @author hjing
* @date 2015-06-19
*/
#pragma once
class CChunk
{
friend class CFixedAllocator;
private:
// 初始化
bool Init(std::size_t blockSize, unsigned char numblocks);
// 释放所有
void Release();
// 分配内存
void* Allocate(std::size_t blockSize);
// 释放内存
void Deallocate(void* p, std::size_t blockSize);
// 数据重置
void Reset(std::size_t blockSize, unsigned char blocks);
// 是否已经满了
inline bool IsFilled() const {return blocksAvailable_ == 0;}
/// Returns true if block at address P is inside this Chunk.
// chunklength = bolcksize * numblocks
inline bool HasBlock( void * p, std::size_t chunkLength ) const
{
unsigned char * pc = static_cast< unsigned char * >( p );
return ( pData_ <= pc ) && ( pc < pData_ + chunkLength );
}
// 是否全部是空着的了,与IsFilled相反
inline bool HasAvailable( unsigned char numBlocks ) const
{
return ( blocksAvailable_ == numBlocks );
}
unsigned char* pData_; // 原始内存,连续的
unsigned char firstAvailableBlock_; // 第一个可用的block的序号,从0开始
unsigned char blocksAvailable_; // 可用的block个数
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Chunk.cpp
#include "StdAfx.h"
#include "Chunk.h"
/** @fn void CChunk::Init(std::size_t bolckSize, unsigned char blocks)
* @brief Init
* @param (IN) std::size_t bolckSize
* @param (IN) unsigned char blocks
* @param (OUT)
* @return void
*/
bool CChunk::Init(std::size_t blockSize, unsigned char numblocks)
{
assert(blockSize > 0);
assert(numblocks > 0);
// 此处为什么可用直接用(),而不是new[]数组呢?是因为直接调用了operator new,分配的内存大小是对的
// 如果直接用pData_ = new char(10)和pData_ = new char[10];是有区别的,第一句值分配1个字节的内存
pData_ = static_cast<unsigned char*>(::operator new (numblocks * blockSize)); // 此处使用C++的new
Reset(blockSize, numblocks);
return true;
}
/** @fn void CChunk::Release()
* @brief Release
* @param (OUT)
* @return void
*/
void CChunk::Release()
{
::operator delete (pData_);
blocksAvailable_ = 0;
firstAvailableBlock_ = 0;
}
/** @fn void* CChunk::Allocate(std::size_t blockSize)
* @brief Allocate
* @param (IN) std::size_t blockSize
* @param (OUT)
* @return void*
*/
void* CChunk::Allocate(std::size_t blockSize)
{
if (!blocksAvailable_)
{
return NULL;
}
unsigned char* pResult = pData_ + (firstAvailableBlock_ * blockSize); // 首地址
firstAvailableBlock_ = (*pResult);
--blocksAvailable_;
return pResult;
}
/** @fn void CChunk::Deallocate(void* p, std::size_t blockSize)
* @brief Deallocate
* @param (IN) void * p
* @param (IN) std::size_t blockSize
* @param (OUT)
* @return void
*/
void CChunk::Deallocate(void* p, std::size_t blockSize)
{
assert(p >= pData_); // 必须来自于pdata_的内存
unsigned char* toRelease = static_cast<unsigned char*>(p);
assert((toRelease - pData_) % blockSize == 0); // 必须释放block的首地址
unsigned char index = static_cast<unsigned char>((toRelease - pData_) / blockSize); // 需要释放的block号
*toRelease = firstAvailableBlock_; // 这条语句很关键!!!如0,1,2分配了,firstAvailableBlock_变为了3,释放0,这个时候再把0的首地址值设置为3
// 下面一句first设置为0,下次分配分配刚刚释放的0的,并且!把first会设置为3,即释放后,可用的firs会变为3,
// 而不是0下面的1,即内存不是按照顺序释放的也是可以的。充分的利用了空余的空间的首地址
firstAvailableBlock_ = index;
//assert(firstAvailableBlock_ == (toRelease == (toRelease - pData_) / blockSize));
++blocksAvailable_;
}
/** @fn void CChunk::Reset(std::size_t blockSize, size_t blocks)
* @brief Reset
* @param (IN) std::size_t blockSize
* @param (IN) size_t blocks
* @param (OUT)
* @return void
*/
void CChunk::Reset(std::size_t blockSize, unsigned char numblocks)
{
firstAvailableBlock_ = 0;
blocksAvailable_ = numblocks;
unsigned char* p = pData_;
for (unsigned char i = 0; i < numblocks; p += blockSize)
{
*p = ++i; // 每块未使用的block块首地址的内容都是指向下一个block序号
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FixedAllocator.h
/** @file FixedAllocator.h
* @note HangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* @brief 每个CFixAllocator包含有多个Chunk,每个Chunk的含义是一样的,只是编号不同
每个Chunk最大能够支持255个block,每个CFixAllocator的空间称为一页
每页的大小是固定的。如521Byte,1024Byte等
每个Chunk中的Block大小也是固定的。如该FixAllocator中的Block大小为16,而页面大小是512则每个Chunk的BlockNum为512/16
* @author hjing
* @date 2015-06-19
*/
#pragma once
#include "Chunk.h"
#include <vector>
using namespace std;
class CFixedAllocator
{
typedef vector<CChunk>::iterator CItor;
typedef vector<CChunk>::const_iterator ConstItor;
public:
CFixedAllocator();
~CFixedAllocator();
void Initialize( std::size_t blockSize, std::size_t pageSize );
// 分配一个blocksize出去
void *Allocate(void);
bool Deallocate(void* p, CChunk* phint);
bool TrimChunkList( void );
inline std::size_t BlockSize() const { return blockSize_; }
// 释放空的chunk
bool TrimEmptyChunk();
const CChunk * HasBlock( void * p ) const
{
const std::size_t chunkLength = numBlocks_ * blockSize_;
for ( ConstItor it( chunks_.begin() ); it != chunks_.end(); ++it )
{
const CChunk & chunk = *it;
if ( chunk.HasBlock( p, chunkLength ) )
return &chunk;
}
return NULL;
}
inline CChunk * HasBlock( void * p )
{
return const_cast< CChunk * >(
const_cast< const CFixedAllocator * >( this )->HasBlock( p ) );
}
private:
// 新建一个chunk
bool MakeNewChunk();
// 通过指针查找属于哪个chunk
CChunk * VicinityFind( void * p ) const;
// 真正的释放p
void DoDeallocate(void * p);
std::size_t blockSize_; // 每个block的大小,每个block不建议超过64byte
unsigned char numBlocks_;// 每个chunk的block个数,每个chunk最多只有255个block
vector<CChunk> chunks_;
CChunk* allocChunk_; // 最近一次分配所使用的chunk,提高分配效率
CChunk* deallocChunk_; // 指向归还所用的最后那个chunk,提高释放效率。释放block的chunk
// 指向一个全部为空的chunk,即该chunk中所有的block都可用。 Pointer to the only empty Chunk if there is one, else NULL.
// 另外需要保证整个chunks_中最多只有一个Chunk是完全空白可用的(也可能没有完全空白的chunk),不要浪费空间
CChunk* emptyChunk_;
static unsigned char MinObjectsPerChunk_; // chunk最小个数
static unsigned char MaxObjectsPerChunk_; // chunk最大个数
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FixedAllocator.cpp
#include "StdAfx.h"
#include "FixedAllocator.h"
unsigned char CFixedAllocator::MinObjectsPerChunk_ = 8;
unsigned char CFixedAllocator::MaxObjectsPerChunk_ = UCHAR_MAX;
/** @fn CFixedAllocator::CFixedAllocator()
* @brief CFixedAllocator
* @param (OUT)
* @return
*/
CFixedAllocator::CFixedAllocator()
: blockSize_(0),
numBlocks_(0),
chunks_(0),
allocChunk_(NULL),
deallocChunk_(NULL),
emptyChunk_(NULL)
{
}
/** @fn CFixedAllocator::~CFixedAllocator()
* @brief ~CFixedAllocator
* @param (OUT)
* @return
*/
CFixedAllocator::~CFixedAllocator()
{
for ( CItor it = chunks_.begin(); it != chunks_.end(); ++it)
{
it->Release();
}
}
/** @fn void CFixedAllocator::Initialize(std::size_t blockSize, std::size_t pageSize)
* @brief Initialize
* @param (IN) std::size_t blockSize
* @param (IN) std::size_t pageSize
* @param (OUT)
* @return void
*/
void CFixedAllocator::Initialize(std::size_t blockSize, std::size_t pageSize)
{
blockSize_ = blockSize;
std::size_t numBlocks = pageSize / blockSize;
if (numBlocks > MaxObjectsPerChunk_)
{
numBlocks = MaxObjectsPerChunk_;
}
else if (numBlocks < MinObjectsPerChunk_)
{
numBlocks = MinObjectsPerChunk_;
}
numBlocks_ = static_cast<unsigned char>(numBlocks);
}
/** @fn void * CFixedAllocator::Alloc(void)
* @brief Alloc
* @param (IN) void
* @param (OUT)
* @return void *
*/
void* CFixedAllocator::Allocate(void)
{
if (allocChunk_ == 0 || allocChunk_->IsFilled())
{
//
if (NULL != emptyChunk_)
{
allocChunk_ = emptyChunk_;
emptyChunk_ = NULL;
}
// allocchunk不可用,线性查找或则新建一个chunk
CItor itfind = chunks_.begin();
for (;;++itfind)
{
if (itfind == chunks_.end())
{
if (!MakeNewChunk())
{
return NULL;
}
itfind = chunks_.end() - 1;
assert(!itfind->IsFilled());
allocChunk_ = &*itfind;
break;
}
if (!itfind->IsFilled())
{
allocChunk_ = &*itfind;
break;
}
}
}
else if (allocChunk_ == emptyChunk_)
{
emptyChunk_ = NULL;
}
assert(allocChunk_ != 0);
assert(allocChunk_->blocksAvailable_ > 0);
return allocChunk_->Allocate(blockSize_);
}
/** @fn void* CFixedAllocator::Deallocate(void* p)
* @brief DealAlloc
* @param (IN) void * p
* @param (OUT)
* @return void*
*/
bool CFixedAllocator::Deallocate(void* p, CChunk* phint)
{
CChunk* fonudChunk = (NULL == phint) ? VicinityFind(p) : phint;
if ( NULL == fonudChunk)
{
// 不合法的p
return false;
}
deallocChunk_ = fonudChunk;
DoDeallocate(p);
return true;
}
/** @fn bool CFixedAllocator::MakeNewChunk()
* @brief MakeNewChunk
* @param (OUT)
* @return bool
*/
bool CFixedAllocator::MakeNewChunk()
{
bool allocated = false;
try
{
std::streamsize size = chunks_.size();
if (chunks_.capacity() == size)
{
if (0 == size)
{
size = 4;
}
chunks_.reserve(size * 2); // 主动控制chunks的大小,不用vector的能力
}
CChunk newChunk;
allocated = newChunk.Init(blockSize_, numBlocks_);
if (allocated)
{
chunks_.push_back(newChunk);
}
}
catch (...)
{
}
return allocated;
}
/** @fn CChunk * CFixedAllocator::VicinityFind(void * p) const
* @brief 通过指针查找属于哪个chunk
* @param (IN) void * p
* @param (OUT)
* @return CChunk *
*/
CChunk * CFixedAllocator::VicinityFind(void * p) const
{
if (chunks_.empty())
{
return NULL;
}
assert(deallocChunk_ != NULL);
const std::size_t chunkLength = numBlocks_ * blockSize_;
// 向前和向后找
CChunk* lo = deallocChunk_;
CChunk* hi = deallocChunk_ + 1;
const CChunk* loBound = &chunks_.front();
const CChunk* hiBound = &chunks_.back() + 1; // 无效值,chunks.end();
if (hi == hiBound)
{
hi = NULL;
}
for (;;)
{
// 向begin方向找
if (lo)
{
if ( lo->HasBlock( p, chunkLength ) )
{
return lo;
}
if ( lo == loBound )
{
lo = NULL;
if ( NULL == hi )
{
break;
}
}
else
{
--lo;
}
}
// 向end方向找
if (hi)
{
if ( hi->HasBlock( p, chunkLength ) )
{
return hi;
}
if ( ++hi == hiBound )
{
hi = NULL;
if ( NULL == lo )
{
break;
}
}
}
}
return NULL;
}
/** @fn void CFixedAllocator::DoDeallocate(void * p)
* @brief 真正的释放p
* @param (IN) void * p
* @param (OUT)
* @return void
*/
void CFixedAllocator::DoDeallocate(void * p)
{
// Show that deallocChunk_ really owns the block at address p.
assert( deallocChunk_->HasBlock( p, numBlocks_ * blockSize_ ) );
// Either of the next two assertions may fail if somebody tries to
// delete the same block twice.
assert( emptyChunk_ != deallocChunk_ );
assert( !deallocChunk_->HasAvailable( numBlocks_ ) );
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
// call into the chunk, will adjust the inner list but won't release memory
// 释放p所指的那块block
deallocChunk_->Deallocate(p, blockSize_);
// 如果全部被释放了,即p所指向的block全部可用了,需要清空一下内存,保证它不总是占用着真实的内存
if ( deallocChunk_->HasAvailable( numBlocks_ ) )
{
assert( emptyChunk_ != deallocChunk_ ); // emptyChunk肯定是全部为空的,而deallocChunk_是刚刚才释放为空,前面肯定是被占用着的
// deallocChunk_ is empty, but a Chunk is only released if there are 2
// empty chunks. Since emptyChunk_ may only point to a previously
// cleared Chunk, if it points to something else besides deallocChunk_,
// then FixedAllocator currently has 2 empty Chunks.
// 避免边界条件发生,allocchunk_和dealalloc_都指向最后一个chunk,而该chunk也所剩无几
if ( NULL != emptyChunk_ )
{
// If last Chunk is empty, just change what deallocChunk_
// points to, and release the last. Otherwise, swap an empty
// Chunk with the last, and then release it.
CChunk * lastChunk = &chunks_.back();
if ( lastChunk == deallocChunk_ )
{
deallocChunk_ = emptyChunk_;
}
else if ( lastChunk != emptyChunk_ )
{
std::swap( *emptyChunk_, *lastChunk );
}
assert( lastChunk->HasAvailable( numBlocks_ ) );
lastChunk->Release(); // 如果DoDeallocate后,出现了一个完全空白的blocks,直接将此blocks内存释放出去,不要让它一直占用着
chunks_.pop_back(); // 从chunk弹出
if ( ( allocChunk_ == lastChunk ) || allocChunk_->IsFilled() )
allocChunk_ = deallocChunk_; // 改变allocChunk的位置,如果allocChunk不再使用当allocChunk
}
emptyChunk_ = deallocChunk_;
}
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
}
// FixedAllocator::TrimChunkList ----------------------------------------------
bool CFixedAllocator::TrimChunkList( void )
{
if ( chunks_.empty() )
{
assert( NULL == allocChunk_ );
assert( NULL == deallocChunk_ );
}
if ( chunks_.size() == chunks_.capacity() )
return false;
// Use the "make-a-temp-and-swap" trick to remove excess capacity.
// 这种写法的原理如下,原作者写的一句话把很多东西省略了
// vector<CChunk> vsTmp(chunks_); vsTmp的值就是chunks_,比如chunks_的大小为100
// 此时vsTmp的capacity值就是100,但是chunks_的capacity肯定比100大,估计在120以上
// swap一下,chunks_的capacity变回了100。vsTmpl临时变量,退出函数,被销毁,不用理睬
(vector<CChunk>( chunks_ )).swap( chunks_ );
return true;
}
// FixedAllocator::TrimEmptyChunk ---------------------------------------------
bool CFixedAllocator::TrimEmptyChunk( void )
{
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
if ( NULL == emptyChunk_ ) return false;
// If emptyChunk_ points to valid Chunk, then chunk list is not empty.
assert( !chunks_.empty() );
// And there should be exactly 1 empty Chunk.
//assert( 1 == CountEmptyChunks() );
CChunk * lastChunk = &chunks_.back();
if ( lastChunk != emptyChunk_ )
std::swap( *emptyChunk_, *lastChunk );
assert( lastChunk->HasAvailable( numBlocks_ ) );
lastChunk->Release();
chunks_.pop_back();
if ( chunks_.empty() )
{
allocChunk_ = NULL;
deallocChunk_ = NULL;
}
else
{
if ( deallocChunk_ == emptyChunk_ )
{
deallocChunk_ = &chunks_.front();
assert( deallocChunk_->blocksAvailable_ < numBlocks_ );
}
if ( allocChunk_ == emptyChunk_ )
{
allocChunk_ = &chunks_.back();
assert( allocChunk_->blocksAvailable_ < numBlocks_ );
}
}
emptyChunk_ = NULL;
//assert( 0 == CountEmptyChunks() );
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SmallObjAllocator.h
#pragma once
#include "FixedAllocator.h"
class CSmallObjAllocator
{
protected:
CSmallObjAllocator(std::size_t pageSize, std::size_t maxObjectSize, std::size_t blockSize);
~CSmallObjAllocator();
public:
void* Allocate(std::size_t numBytes);
void Deallocate(void* p, std::size_t size);
void Deallocate(void* p);
private:
// 禁止拷贝
CSmallObjAllocator();
CSmallObjAllocator(const CSmallObjAllocator&);
CSmallObjAllocator & operator = ( const CSmallObjAllocator & );
// 字节增长,如4字节一个排列,则是4,8,12等不同的blocks
std::size_t GetOffset(std::size_t numBytes, std::size_t objectAddSize)
{
return (numBytes + objectAddSize - 1) / objectAddSize;
}
inline std::size_t GetMaxObjectSize() const
{
return maxSmallObjectSize_;
}
inline std::size_t GetAlignment() const { return objectAlignSize_; }
bool TrimExcessMemory( void );
bool TrimChunkList( void );
private:
CFixedAllocator* pool_; // 数组
// 最大支持的blocks大小
std::size_t maxSmallObjectSize_;
/// Size of alignment boundaries.
const std::size_t objectAlignSize_;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SmallObjAllocator.cpp
#include "StdAfx.h"
#include "SmallObjAllocator.h"
// c++默认分配器
// DefaultAllocator -----------------------------------------------------------
/** @ingroup SmallObjectGroupInternal
Calls the default allocator when SmallObjAllocator decides not to handle a
request. SmallObjAllocator calls this if the number of bytes is bigger than
the size which can be handled by any FixedAllocator.
@param numBytes number of bytes
@param doThrow True if this function should throw an exception, or false if it
should indicate failure by returning a NULL pointer.
*/
void * DefaultAllocator( std::size_t numBytes)
{
return operator new(numBytes);
}
void DefaultDeallocator( void * p )
{
::operator delete( p );
}
CSmallObjAllocator::CSmallObjAllocator(std::size_t pageSize, std::size_t maxObjectSize, std::size_t blockSize)
: pool_(NULL),
maxSmallObjectSize_(maxObjectSize),
objectAlignSize_(blockSize)
{
const std::size_t allocCount = GetOffset(maxObjectSize, blockSize); // 可用划分出多少个FixAllocator,每个FixAllocator是个
pool_ = new CFixedAllocator[allocCount];
for (std::size_t i = 0; i < allocCount; ++i)
{
pool_[i].Initialize((i + 1) * blockSize, pageSize);
}
}
/** @fn void* CSmallObjAllocator::Allocate(std::size_t numBytes)
* @brief Allocate
* @param (IN) std::size_t numBytes
* @param (OUT)
* @return void*
*/
void* CSmallObjAllocator::Allocate(std::size_t numBytes)
{
if ( numBytes > GetMaxObjectSize() )
return DefaultAllocator( numBytes);
assert( NULL != pool_ );
if ( 0 == numBytes ) numBytes = 1;
const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1;
const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() );
(void) allocCount;
assert( index < allocCount );
CFixedAllocator & allocator = pool_[ index ];// 找到numBytes最适合的CFixedAllocator
assert( allocator.BlockSize() >= numBytes );
assert( allocator.BlockSize() < numBytes + GetAlignment() );
void * place = allocator.Allocate();
if ( ( NULL == place ) && TrimExcessMemory() )
place = allocator.Allocate();
return place;
}
/** @fn void CSmallObjAllocator::Deallocate(void* p, std::size_t size)
* @brief Deallocate
* @param (IN) void * p
* @param (IN) std::size_t size
* @param (OUT)
* @return void
*/
void CSmallObjAllocator::Deallocate(void* p, std::size_t numBytes)
{
if ( NULL == p ) return;
if ( numBytes > GetMaxObjectSize() )
{
DefaultDeallocator( p );
return;
}
assert( NULL != pool_ );
if ( 0 == numBytes ) numBytes = 1;
const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1;
const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() );
(void) allocCount;
assert( index < allocCount );
CFixedAllocator & allocator = pool_[ index ];
assert( allocator.BlockSize() >= numBytes );
assert( allocator.BlockSize() < numBytes + GetAlignment() );
const bool found = allocator.Deallocate( p, NULL );
(void) found;
assert( found );
}
void CSmallObjAllocator::Deallocate(void* p)
{
if ( NULL == p ) return;
assert( NULL != pool_ );
CFixedAllocator * pAllocator = NULL;
const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() );
CChunk * chunk = NULL;
for ( std::size_t ii = 0; ii < allocCount; ++ii )
{
chunk = pool_[ ii ].HasBlock( p );
if ( NULL != chunk )
{
pAllocator = &pool_[ ii ];
break;
}
}
if ( NULL == pAllocator )
{
DefaultDeallocator( p );
return;
}
assert( NULL != chunk );
const bool found = pAllocator->Deallocate( p, chunk );
(void) found;
assert( found );
}
/** @fn CSmallObjAllocator::~CSmallObjAllocator()
* @brief ~CSmallObjAllocator
* @param (OUT)
* @return
*/
CSmallObjAllocator::~CSmallObjAllocator()
{
delete [] pool_;
}
bool CSmallObjAllocator::TrimExcessMemory( void )
{
bool found = false;
const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() );
std::size_t i = 0;
for ( ; i < allocCount; ++i )
{
if ( pool_[ i ].TrimEmptyChunk() )
found = true;
}
for ( i = 0; i < allocCount; ++i )
{
if ( pool_[ i ].TrimChunkList() )
found = true;
}
return found;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SmallObject.h
#pragma once
#include "SmallObjAllocator.h"
template<typename T>
class CSingletonHolder
{
public:
static T& Instance()
{
static T* pInstance = NULL;
if (!pInstance)
{
pInstance = new T;
}
return *pInstance;
}
private:
CSingletonHolder(){}
};
#define DEFAULT_CHUNK_SIZE 4096 // 缺省大小,最大分配4M空间供block使用
#define MAX_SMALL_OBJECT_SIZE 256 // 每个对象大小为64byte,大于64的不建议使用内存池
#define LOKI_DEFAULT_OBJECT_ALIGNMENT 4 // 对齐大小
template<std::size_t chunkSize = DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT
>
class CSmallObjectSingleton: public CSmallObjAllocator
{
typedef CSmallObjectSingleton<chunkSize, maxSmallObjectSize, objectAlignSize> MyAllocator;
typedef CSingletonHolder<MyAllocator> MyAlloc;
friend class CSingletonHolder<MyAllocator>;
public:
/// Returns reference to the singleton.
inline static CSmallObjectSingleton & Instance( void )
{
return MyAlloc::Instance();
}
protected:
// 构造
CSmallObjectSingleton(void)
: CSmallObjAllocator(chunkSize, maxSmallObjectSize, objectAlignSize)
{
}
virtual ~CSmallObjectSingleton(void)
{
}
public:
// 清空多余内存
static void ClearExtraMemory( void )
{
Instance().TrimExcessMemory();
}
static void* operator new(std::size_t size)
{
return MyAlloc::Instance().Allocate( size);
}
static void operator delete(void* p, std::size_t size)
{
MyAlloc::Instance().Deallocate( p, size );
}
static void operator delete(void* p)
{
MyAlloc::Instance().Deallocate( p );
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
简单使用举例
MyAllocation.h
#pragma once
#include "SmallObject.h"
typedef CSmallObjectSingleton<4096, 64, 4> SmallObjectParent;
class CMyAllocation: public SmallObjectParent
{
public:
CMyAllocation(void);
~CMyAllocation(void);
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void playexe::OnTestClicked()
{
CMyAllocation aa;
char* pA1 = static_cast<char*>(aa.Allocate(21));
char* pA2 = static_cast<char*>(aa.Allocate(21));
char* pA3 = static_cast<char*>(aa.Allocate(21));
aa.Deallocate(pA1);
char* pA4 = static_cast<char*>(aa.Allocate(21));
return;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- 第四章(小型对象分配技术:smart-object allocation)
- 小型对象分配技术
- Modern C++ Design 笔记 第四章 Small-Object Allocation
- 小型对象内存分配
- C/C++小型对象分配的性能测试笔记
- CVM Object Allocation
- CVM Object Allocation
- smart 技术
- 使用.net技术创建一个小型对象池
- Effective Modern C++ 笔记 第四章 Smart Pointers
- 第四章调试技术
- 第四章 Servlet技术
- 第四章:调试技术
- 第四章--调试技术
- 小对象的分配技术(结)
- smart client 技术
- Smart Client技术应用
- 磁盘SMART技术应用
- x86 gcc 里绝对值优化求法
- 各种编码UNICODE、UTF-8、ANSI、ASCII、GB2312、GBK详解
- Netbeans打开包含中文文件时提示错误
- java笔记之二
- java 实现生成excel表头
- 第四章(小型对象分配技术:smart-object allocation)
- bzoj3651&3081: 网络通信
- java笔记之三
- Bilateral Filtering(双边滤波)
- .Net——使用.net内置处理程序处理自定义节点Demo
- Error: [ng:areq] http://errors.angularjs.org...undefined
- 黑马程序员--基本运算
- XUtil框架的使用
- SpringMVC入门例子