|
|
设计思路:
以页面为单位预先分配一定数量的对象给客户程序使用,用完再归还回来。
采用页面链表技术,理论上分配数量无上限。
页面中的对象用堆管理,请求时从堆顶移出一个给它使用,归还时放回堆顶。
当页面用完时分配新页面在页面链表的未尾。
需要客户程序额外记录一个页面索引值,归还时对号入坐。
跟踪空闲对象数量,归还时判断空闲对象数量是否大于等于预定值(这里取2个页面数量值),
超过的话释放空闲页面,直至空闲对象数量小于等于预定值(这里取1个页面数量值)。
每页面对象数量可通过带参数的构造函数设置,低于16时取16(如果低于16还不如用数组),
但具体取多少应根据实际情况而定,如果对象较小(低于128字节),此数值可以取大一点,如取
1024的话,一个页面也只占用128K的内存,对于现在的PC机来说微不足道。还有对象需要的数量变
动较大较频繁的话此值也应取大一点,过小的话分配和释放页面过多会降低程序运行速度。我推荐
的取值是估算你需要的最大量(这时对象请求归还操作在一个页面里,最佳情况),再计算目标平台内
存容量的1%(毕竟这不是程序的全部,还有其它模块也需要占用内存),权衡利弊取小值。
用法很简单:
ObjectBuffer<int> ob; //定义整型ObjectBuffer对象,无参构造,每页面对象数量取16
int* p[48]; //客户程序装对象的数组
unsigned long page[48]; //客户程序记录页面索引的数组
for( int i = 0; i < 48; i++ )
{
p = NULL;
page = 0;
ob.RequestObject( &p, page ); //请求对象
*p = 0; //请求来的对象是对象指针
}
for( i = 0; i < 32; i++ )
{
ob.ReturnObject( &p, page ); //归还对象
}
作者心声:
有用得着的话就拿去,但有一点就是请大家不要只看不说,大家多多提意见,比如发现什么错误啊,或者是
什么地方需要改进啊,或者是有更好的思路啊,大家一起分享哈嘛。我把它公布出来也是让大家一起分享嘛,所以请大家不
要只看不说,更或是用了也不说话。好了,不多说了,最后欢迎大家灌水,拍砖吧![em13][em13][em13][em13]
/*************ObjectBuffer1.0****************/
//对象缓冲器类模版,缓冲器预先分配一定数量的对象,当用到时就从缓冲器
//请求,不用时归还缓冲器,采用页链表分配技术使缓冲器理论上无分配上限
//
const unsigned long ObjectOfPageMin = 16; //每页中对象数量的最低值16
//低于此值时缓冲器将失去意义
template <class T>
class ObjectBuffer
{
public:
ObjectBuffer();
//ulObjectPage,每页上对象的数量,此值应根据对象大小、使用
//情况统筹选取,以降低内存浪费。当小于16时取值16。
ObjectBuffer( unsigned long ulObjectOfPage );
~ObjectBuffer();
//当要用一个对象时,就用RequestObject请求
bool RequestObject( T** pObjectPointer, unsigned long& ulPage );
//当不用对象时调用ReturnObject归还
bool ReturnObject( T** pObjectPointer, unsigned long& ulPage );
//pObjectPointer参数为指向对象指针的指针 ulPage参数为对象所在的页
//注意:当归还对象后,*pObjectPointer == NULL、ulPage == 0
private:
struct SPage
{
T* m_pObjects;//对象数组
T** m_ppObjectStack;//对象堆,堆中存储的是对象指针
unsigned long m_ulTop; //堆顶,当为0时说明对象已用完
unsigned long m_ulObjectCount; //对象数量
SPage* m_pFront; //前一页
SPage* m_pBack; //后一页
SPage()
{
m_pObjects = NULL; //对象数组
m_ppObjectStack = NULL; //对象堆,堆中存储的是对象指针
m_ulTop = 0; //堆顶,当为0时说明对象已用完
m_pFront = NULL; //前一页
m_pBack = NULL; //后一页
m_ulObjectCount = 0; //对象数量
unsigned long ulObjectOfPage = ObjectOfPageMin;
m_pObjects = new T[ ulObjectOfPage ];
m_ppObjectStack = new T*[ ulObjectOfPage ];
if( NULL == m_pObjects || NULL == m_ppObjectStack )return;
for( int i = 0; i < ulObjectOfPage; i++ )
m_ppObjectStack = &m_pObjects;
m_ulTop = ulObjectOfPage;
m_ulObjectCount = ulObjectOfPage; //对象数量
}
SPage( unsigned long ulObjectOfPage )
{
m_pObjects = NULL; //对象数组
m_ppObjectStack = NULL; //对象堆,堆中存储的是对象指针
m_ulTop = 0; //堆顶,当为0时说明对象已用完
m_pFront = NULL; //前一页
m_pBack = NULL; //后一页
m_ulObjectCount = 0; //对象数量
if( ulObjectOfPage < ObjectOfPageMin )ulObjectOfPage = ObjectOfPageMin;
m_pObjects = new T[ ulObjectOfPage ];
m_ppObjectStack = new T*[ ulObjectOfPage ];
if( NULL == m_pObjects || NULL == m_ppObjectStack )return;
for( int i = 0; i < ulObjectOfPage; i++ )
m_ppObjectStack = &m_pObjects;
m_ulTop = ulObjectOfPage;
m_ulObjectCount = ulObjectOfPage; //对象数量
}
~SPage(){ Release(); }
void Release()
{
if( NULL != m_pObjects )delete[] m_pObjects;
if( NULL != m_ppObjectStack )delete[] m_ppObjectStack;
m_pObjects = NULL; //对象数组
m_ppObjectStack = NULL; //对象堆,堆中存储的是对象指针
m_ulObjectCount = 0; //对象数量
m_ulTop = 0; //堆顶,当为0时说明对象已用完
m_pFront = NULL; //前一页
m_pBack = NULL; //后一页
}
bool IsEmpty()
{
return 0 == m_ulTop;
}
bool IsFull()
{
return m_ulTop == m_ulObjectCount;
}
void SetBack( SPage* pBack ){ m_pBack = pBack; }
void SetFront( SPage* pFront ){ m_pFront = pFront; }
T* RequestObject()
{
if( IsEmpty() )return NULL;
m_ulTop--;
return m_ppObjectStack[ m_ulTop ];
}
bool ReturnObject( T* pObject )
{
if( m_ulTop == m_ulObjectCount )return false;
//检查对象是否重复归还
for( unsigned long i = 0; i < m_ulTop; i++ )
{
if( m_ppObjectStack[ i ] == pObject )return false;
}
m_ppObjectStack[ m_ulTop ] = pObject;
m_ulTop++;
return true;
}
};
SPage* m_pBeginPage; //页链表开始页
SPage* m_pEndPage; //页链表结束页
SPage* m_pCurrentPage; //当前操作页
unsigned long m_ulCurrentPageNumber; //当前页编号
unsigned long m_ulPageCount; //页数量
unsigned long m_ulObjectOfPage; //每页中对象的数量
unsigned long m_ulIdleObjectCount; //空闲对象数量
};
template <class T>
ObjectBuffer<T>::ObjectBuffer()
{
m_pBeginPage = NULL; //页链表开始页
m_pCurrentPage = NULL; //当前操作页
m_pEndPage = NULL; //页链表结束页
m_ulPageCount = 0; //页数量
m_ulCurrentPageNumber = 0; //当前页编号
m_ulIdleObjectCount = 0; //空闲对象数量
m_ulObjectOfPage = ObjectOfPageMin;
m_pCurrentPage = m_pEndPage = m_pBeginPage = new SPage( m_ulObjectOfPage );
if( NULL == m_pBeginPage )return;
m_ulPageCount = 1;
m_ulCurrentPageNumber = 1; //当前页编号
m_ulIdleObjectCount += m_ulObjectOfPage;//空闲对象数量增加一个页面的数量
}
template <class T>
ObjectBuffer<T>::ObjectBuffer( unsigned long ulObjectOfPage )
{
m_pBeginPage = NULL; //页链表开始页
m_pCurrentPage = NULL; //当前操作页
m_pEndPage = NULL; //页链表结束页
m_ulPageCount = 0; //页数量
m_ulCurrentPageNumber = 0; //当前页编号
m_ulIdleObjectCount = 0; //空闲对象数量
m_ulObjectOfPage = ulObjectOfPage;
if( m_ulObjectOfPage < ObjectOfPageMin )m_ulObjectOfPage = ObjectOfPageMin;
m_pCurrentPage = m_pEndPage = m_pBeginPage = new SPage( m_ulObjectOfPage );
if( NULL == m_pBeginPage )return;
m_ulPageCount = 1;
m_ulCurrentPageNumber = 1; //当前页编号
m_ulIdleObjectCount += m_ulObjectOfPage;//空闲对象数量增加一个页面的数量
}
template <class T>
ObjectBuffer<T>::~ObjectBuffer()
{
while( NULL != m_pBeginPage )
{
m_pCurrentPage = m_pBeginPage;
m_pBeginPage = m_pBeginPage->m_pBack;
m_pCurrentPage->Release();
delete m_pCurrentPage;
}
m_pBeginPage = NULL; //页链表开始页
m_pCurrentPage = NULL; //当前操作页
m_pEndPage = NULL; //页链表结束页
m_ulPageCount = 0; //页数量
m_ulCurrentPageNumber = 0; //当前页编号
m_ulIdleObjectCount = 0; //空闲对象数量
}
template <class T>
bool ObjectBuffer<T>::RequestObject( T** pObjectPointer, unsigned long& ulPage )
{
for( unsigned long i = 0; i < m_ulPageCount; i++ )
{
if( !m_pCurrentPage->IsEmpty() )//如果不为空就请求一个对象
{
*pObjectPointer = m_pCurrentPage->RequestObject();
ulPage = m_ulCurrentPageNumber;
m_ulIdleObjectCount--; //一个对象成功分配,空闲对象数量减1
return true;
}
if( m_pCurrentPage == m_pEndPage )//如果到了未尾就从头开始
{
m_pCurrentPage = m_pBeginPage;
m_ulCurrentPageNumber = 1;
}
else
{
m_pCurrentPage = m_pCurrentPage->m_pBack;
m_ulCurrentPageNumber++;
}
}
//如果循环结束还没找到空闲对象,说明页面已经用完,需要分配新页面
SPage* m_pNew = new SPage( m_ulObjectOfPage );
if( NULL == m_pNew )return false;
m_pNew->SetFront( m_pEndPage );
m_pEndPage->SetBack( m_pNew );
m_pEndPage = m_pNew;
m_ulPageCount++;
m_pCurrentPage = m_pEndPage;
m_ulCurrentPageNumber = m_ulPageCount;
m_ulIdleObjectCount += m_ulObjectOfPage; //空闲对象数量增加一个页面的数量
if( !m_pCurrentPage->IsEmpty() )//如果不为空就请求一个对象
{
*pObjectPointer = m_pCurrentPage->RequestObject();
ulPage = m_ulCurrentPageNumber;
m_ulIdleObjectCount--; //一个对象成功分配,空闲对象数量减1
return true;
}
return false;
}
template <class T>
bool ObjectBuffer<T>::ReturnObject( T** pObjectPointer, unsigned long &ulPage )
{
if( NULL == pObjectPointer || NULL == *pObjectPointer ||
0 == ulPage || ulPage > m_ulPageCount )return false;
if( ulPage > m_ulCurrentPageNumber )
{
for( ; m_ulCurrentPageNumber < ulPage; m_ulCurrentPageNumber++ )
{
m_pCurrentPage = m_pCurrentPage->m_pBack;
}
}
if( ulPage < m_ulCurrentPageNumber )
{
for( ; m_ulCurrentPageNumber > ulPage; m_ulCurrentPageNumber-- )
{
m_pCurrentPage = m_pCurrentPage->m_pFront;
}
}
if( !m_pCurrentPage->ReturnObject( *pObjectPointer ) )return false;
*pObjectPointer = NULL;
ulPage = 0;
m_ulIdleObjectCount++; //一个对象成功归还,空闲对象数量加1
//如果空闲对象数量大于2倍页面数量,说明空闲对象太多了,需要释放一些以减少内存占用
if( m_ulIdleObjectCount >= ( m_ulObjectOfPage * 2 ) )
{
SPage* pTemp1 = m_pBeginPage;
SPage* pTemp2 = NULL;
//遍历页面链表,找出空闲页面并释放
while( NULL != pTemp1 )
{
if( m_ulIdleObjectCount <= m_ulObjectOfPage )break;
pTemp2 = pTemp1;
pTemp1 = pTemp1->m_pBack;//向后遍历
//如果为空闲页面
if( pTemp2->IsFull() )
{
//如果是开始页面让开始页面指向下一页面
if( pTemp2 == m_pBeginPage )
{
m_pBeginPage = pTemp2->m_pBack;//让下一页作为新的开始页
m_pBeginPage->m_pFront = NULL;//让新开始页的前一页指向空
//如果和当前页面相同让当前页面指向下一页面
if( pTemp2 == m_pCurrentPage )
{
m_pCurrentPage = pTemp2->m_pBack;
}
pTemp2->Release();
delete pTemp2;
pTemp2 = NULL;
m_ulPageCount--;
m_ulIdleObjectCount -= m_ulObjectOfPage;
continue;
}
//如果是结束页面让结束页面指向上一页面
if( pTemp2 == m_pEndPage )
{
m_pEndPage = pTemp2->m_pFront;//让上一页作为新的结束页
m_pEndPage->m_pBack = NULL;//让新结束页的后一页指向空
//如果和当前页面相同让当前页面指向上一页面
if( pTemp2 == m_pCurrentPage )
{
m_pCurrentPage = pTemp2->m_pFront;
m_ulCurrentPageNumber--;//当前页面编号减1
}
pTemp2->Release();
delete pTemp2;
pTemp2 = NULL;
m_ulPageCount--;
m_ulIdleObjectCount -= m_ulObjectOfPage;
continue;
}
//既不是开始页也不是结束页,只是和当前页相同让当前页指向下一页
if( pTemp2 == m_pCurrentPage )
{
m_pCurrentPage = pTemp2->m_pBack;
m_ulCurrentPageNumber++;//当前页面编号增1
}
pTemp2->m_pFront->m_pBack = pTemp2->m_pBack;
pTemp2->m_pBack->m_pFront = pTemp2->m_pFront;
pTemp2->Release();
delete pTemp2;
pTemp2 = NULL;
m_ulPageCount--;
m_ulIdleObjectCount -= m_ulObjectOfPage;
}
}
}
return true;
}
//end |
|