以前在一个高性能的场合,需要十分频繁的使用临时缓存。由于所需的缓存大小我事先知道,所以我索性开了一块全局缓存,不要骂我土,它背后可以一个崇高的设计哲学:奥坎姆的剃刀。
不过,后边我越看越恶心,越看越想吐,于是就想实现一个分配和释放都为常数时间的MemPool. 虽然内存池是一个老得不老再老的话题,但是我并没有找到一个能达到我要求的设计。
虽然我对C++的任何细节都毫不知情,不过还是免为其难的写了一个有诸多缺陷的XMemPool。
先说下大致思路:
1 POOL将分配划分成两种情况,小缓存分配,大缓存分配。小于4K的我把它当成小缓存。小缓存块BlockSize按8字节步长增长,大块默认按4K步长增长。每种Size的块用两个链表进行管理(free & used)。
2 分配。要是size超过了最大能分配的大小或者池容量超过限制就直接调用系统分配。计算相应块的index(如果是调用系统分配的index会置为-1), 把free list第一个结点移到used list的第一个结点
3 释放。 如果块的index为-1直接delete。将要释放的块直接移动到free list的第一个结点。
这样的话缺点也是相当明显的:
1 用户必要从Block获取缓存
2 用户非常有必要对缓存大小事先按需求进行合理估计。
 1 #ifndef _X_MEM_POOL_H_
#ifndef _X_MEM_POOL_H_
 2 #define _X_MEM_POOL_H_
#define _X_MEM_POOL_H_
 3
 4 //! (1)alloc:O(1)
//! (1)alloc:O(1)
 5 //! (2)free :O(1)
//! (2)free :O(1)
 6 //! (3)not thread safe
//! (3)not thread safe
 7
 8 class XMemPool;
class XMemPool;
 9 class XMemBlock
class XMemBlock
10

 {
{
11 public:
public:
12 XMemBlock( const int& index, const size_t& size ):
    XMemBlock( const int& index, const size_t& size ):
13 _index( index ),
      _index( index ),
14 _next( 0 ),
      _next( 0 ),
15 _pre( 0 ),
      _pre( 0 ),
16 _size( size )
      _size( size )
17
 
     {
{
18 _data = new char[size];
        _data = new char[size];
19 }
    }
20 ~XMemBlock()
    ~XMemBlock()
21
 
     {
{
22 delete []_data;
        delete []_data;
23 }
    }
24
25 public:
public:
26 friend class XMemPool;
    friend class XMemPool;
27 template<class T>
    template<class T>
28
 T* getMem() const
    T* getMem() const  { return (T*)_data; }
{ return (T*)_data; }
29
30 private:
private:
31 const int    _index;
    const int    _index;
32 const size_t _size;
    const size_t _size;
33 char        *_data;
    char        *_data;
34 XMemBlock  *_next;
    XMemBlock  *_next;
35 XMemBlock  *_pre;
    XMemBlock  *_pre;
36 };
};
37
38 const size_t S_MEM_THRE        = 4096;//4K
const size_t S_MEM_THRE        = 4096;//4K
39 const size_t S_POOL_STEP       = 8;
const size_t S_POOL_STEP       = 8;
40 const size_t LARGE_POOL_STEP   = 4096;//4K
const size_t LARGE_POOL_STEP   = 4096;//4K
41 const size_t SMAX_SUB_POOL_CAP = 128;
const size_t SMAX_SUB_POOL_CAP = 128;
42 const size_t LMAX_SUB_POOL_CAP = 64;
const size_t LMAX_SUB_POOL_CAP = 64;
43
44 class XMemPool
class XMemPool
45

 {
{
46 public:
public:
47
 /**//*
    /**//* 
48 maxBlockSize 此内存池能分配的最大的内存
    maxBlockSize 此内存池能分配的最大的内存
49 maxSubPoolCapability 每个子内存池的最大容量
    maxSubPoolCapability 每个子内存池的最大容量
50 poolXep 相邻子内存池之间的BlockSize的差距,即每个子内存池大小为poolXep的整数倍
    poolXep 相邻子内存池之间的BlockSize的差距,即每个子内存池大小为poolXep的整数倍
51
52 这里小块的容量,大小写死了的,只有大块的可以配置
    这里小块的容量,大小写死了的,只有大块的可以配置
53 */
    */
54 XMemPool( const size_t& maxBlockSize, const size_t& lmaxSubPoolCapability = LMAX_SUB_POOL_CAP,\
    XMemPool( const size_t& maxBlockSize, const size_t& lmaxSubPoolCapability = LMAX_SUB_POOL_CAP,\
55 const size_t& lpoolXep = LARGE_POOL_STEP );
        const size_t& lpoolXep = LARGE_POOL_STEP );
56 ~XMemPool();
    ~XMemPool();
57 public:
public:
58 XMemBlock *alloc( size_t size );
    XMemBlock *alloc( size_t size );
59 void free( XMemBlock* block );
    void free( XMemBlock* block );
60 void destroy();
    void destroy();
61
 size_t getTotalMemSize() const
    size_t getTotalMemSize() const  { return _totalMemSize; };
{ return _totalMemSize; };
62
63 private:
private:
64 const size_t _maxBlockSize;  //最大能分配的内存块
    const size_t _maxBlockSize;  //最大能分配的内存块
65 const size_t _lmaxSubPoolCapability; //每种块的最大小数(大块)
    const size_t _lmaxSubPoolCapability; //每种块的最大小数(大块)
66 static const size_t\
    static const size_t\
67 _smaxSubPoolCapability = SMAX_SUB_POOL_CAP;//每种块的最大小数(小块)
                 _smaxSubPoolCapability = SMAX_SUB_POOL_CAP;//每种块的最大小数(小块)
68 const size_t _lpoolXep; //大块的增长步长
    const size_t _lpoolXep; //大块的增长步长
69 static const size_t\
    static const size_t\
70 _spoolXep = S_POOL_STEP; //小块的步长
                 _spoolXep = S_POOL_STEP; //小块的步长
71 XMemBlock **_ssubPool[2];//0:free 1:used 小块的链表数组
    XMemBlock **_ssubPool[2];//0:free 1:used 小块的链表数组
72 XMemBlock **_lsubPool[2];//大块的链表数组
    XMemBlock **_lsubPool[2];//大块的链表数组
73 size_t       _ssubPoolNum;//小块的种类个数
    size_t       _ssubPoolNum;//小块的种类个数
74 size_t       _lsubPoolNum;//大块的种类个数
    size_t       _lsubPoolNum;//大块的种类个数
75 size_t      *_lsubPoolSize;//每种size大块的个数
    size_t      *_lsubPoolSize;//每种size大块的个数
76 size_t      *_ssubPoolSize;//每种size小块的个数
    size_t      *_ssubPoolSize;//每种size小块的个数
77 size_t       _totalMemSize;//内存池总容量
    size_t       _totalMemSize;//内存池总容量
78 };
};
79
80 #endif
#endif 
 
  1 XMemPool::XMemPool( const size_t& maxBlockSize, const size_t& lmaxSubPoolCapability, const size_t& lpoolXep ):\
XMemPool::XMemPool( const size_t& maxBlockSize, const size_t& lmaxSubPoolCapability, const size_t& lpoolXep ):\
  2 _maxBlockSize( maxBlockSize ),
_maxBlockSize( maxBlockSize ),
  3 _lmaxSubPoolCapability( lmaxSubPoolCapability ),
_lmaxSubPoolCapability( lmaxSubPoolCapability ),
  4 _lpoolXep( lpoolXep )
_lpoolXep( lpoolXep )
  5

 {
{
  6 _ssubPoolNum = ( S_MEM_THRE + _spoolXep - 1 ) / _spoolXep;
    _ssubPoolNum = ( S_MEM_THRE + _spoolXep - 1 ) / _spoolXep;
  7 _lsubPoolNum = ( _maxBlockSize + _lpoolXep - 1 ) / _lpoolXep;
    _lsubPoolNum = ( _maxBlockSize + _lpoolXep - 1 ) / _lpoolXep;
  8 _totalMemSize = 0;
    _totalMemSize = 0;
  9 _ssubPoolSize = new size_t[_ssubPoolNum];
    _ssubPoolSize = new size_t[_ssubPoolNum];
 10 _lsubPoolSize = new size_t[_lsubPoolNum];
    _lsubPoolSize = new size_t[_lsubPoolNum];
 11 _ssubPool[0] = new XMemBlock*[_ssubPoolNum];
    _ssubPool[0] = new XMemBlock*[_ssubPoolNum];
 12 _ssubPool[1] = new XMemBlock*[_ssubPoolNum];
    _ssubPool[1] = new XMemBlock*[_ssubPoolNum];
 13 for( int i = 0; i < _ssubPoolNum; i++ )
    for( int i = 0; i < _ssubPoolNum; i++ )
 14
 
     {
{
 15 _ssubPool[0][i] = 0;
        _ssubPool[0][i] = 0;
 16 _ssubPool[1][i] = 0;
        _ssubPool[1][i] = 0;
 17 _ssubPoolSize[i] = 0;
        _ssubPoolSize[i] = 0;
 18 }
    }
 19 _lsubPool[0] = new XMemBlock*[_lsubPoolNum];
    _lsubPool[0] = new XMemBlock*[_lsubPoolNum];
 20 _lsubPool[1] = new XMemBlock*[_lsubPoolNum];
    _lsubPool[1] = new XMemBlock*[_lsubPoolNum];
 21 for( int i = 0; i < _lsubPoolNum; i++ )
    for( int i = 0; i < _lsubPoolNum; i++ )
 22
 
     {
{
 23 _lsubPool[0][i] = 0;
        _lsubPool[0][i] = 0;
 24 _lsubPool[1][i] = 0;
        _lsubPool[1][i] = 0;
 25 _lsubPoolSize[i] = 0;
        _lsubPoolSize[i] = 0;
 26 }
    }
 27 }
}
 28
 29 XMemBlock* XMemPool::alloc( size_t size ) //byte unit
XMemBlock* XMemPool::alloc( size_t size ) //byte unit
 30

 {
{
 31 if( size <= S_MEM_THRE )
    if( size <= S_MEM_THRE )
 32
 
     {
{
 33 size_t idx = ( size + _spoolXep - 1 ) / _spoolXep - 1;
        size_t idx = ( size + _spoolXep - 1 ) / _spoolXep - 1;
 34 XMemBlock *block = 0;
        XMemBlock *block = 0;
 35 if( _ssubPool[0][idx] )
        if( _ssubPool[0][idx] )
 36
 
         {
{
 37 block = _ssubPool[0][idx];
            block = _ssubPool[0][idx];
 38 _ssubPool[0][idx] = block->_next;
            _ssubPool[0][idx] = block->_next;
 39 if( _ssubPool[1][idx] )
            if( _ssubPool[1][idx] )
 40 _ssubPool[1][idx]->_pre = block;
                _ssubPool[1][idx]->_pre = block;
 41 block->_next = _ssubPool[1][idx];
            block->_next = _ssubPool[1][idx];
 42 _ssubPool[1][idx] = block;
            _ssubPool[1][idx] = block;
 43 _ssubPool[1][idx]->_pre = 0;
            _ssubPool[1][idx]->_pre = 0;
 44 return block;
            return block;
 45 }
        }
 46 else if( _ssubPoolSize[idx] < _smaxSubPoolCapability )
        else if( _ssubPoolSize[idx] < _smaxSubPoolCapability )
 47
 
         {
{
 48 size_t msize = (idx + 1)*_spoolXep;
            size_t msize = (idx + 1)*_spoolXep;
 49 _totalMemSize += msize;
            _totalMemSize += msize;
 50 block = new XMemBlock( idx, msize );
            block = new XMemBlock( idx, msize );
 51 _ssubPoolSize[idx]++;
            _ssubPoolSize[idx]++;
 52 if( _ssubPool[1][idx] )
            if( _ssubPool[1][idx] )
 53 _ssubPool[1][idx]->_pre = block;
                _ssubPool[1][idx]->_pre = block;
 54 block->_next = _ssubPool[1][idx];
            block->_next = _ssubPool[1][idx];
 55 _ssubPool[1][idx] = block;
            _ssubPool[1][idx] = block;
 56 return block;
            return block;
 57 }
        }
 58 }
    }
 59 else if( size <= _maxBlockSize )
    else if( size <= _maxBlockSize )
 60
 
     {
{
 61 size_t idx = ( size + _lpoolXep - 1 ) / _lpoolXep - 1;
        size_t idx = ( size + _lpoolXep - 1 ) / _lpoolXep - 1;
 62 XMemBlock *block = 0;
        XMemBlock *block = 0;
 63 if( _lsubPool[0][idx] )
        if( _lsubPool[0][idx] )
 64
 
         {
{
 65 block = _lsubPool[0][idx];
            block = _lsubPool[0][idx];
 66 _lsubPool[0][idx] = block->_next;
            _lsubPool[0][idx] = block->_next;
 67 if( _lsubPool[1][idx] )
            if( _lsubPool[1][idx] )
 68 _lsubPool[1][idx]->_pre = block;
                _lsubPool[1][idx]->_pre = block;
 69 block->_next = _lsubPool[1][idx];
            block->_next = _lsubPool[1][idx];
 70 _lsubPool[1][idx] = block;
            _lsubPool[1][idx] = block;
 71 _lsubPool[1][idx]->_pre = 0;
            _lsubPool[1][idx]->_pre = 0;
 72 return block;
            return block;
 73 }
        }
 74 else if( _lsubPoolSize[idx] < _lmaxSubPoolCapability )
        else if( _lsubPoolSize[idx] < _lmaxSubPoolCapability )
 75
 
         {
{
 76 size_t msize = (idx + 1)*_lpoolXep;
            size_t msize = (idx + 1)*_lpoolXep;
 77 _totalMemSize += msize;
            _totalMemSize += msize;
 78 block = new XMemBlock( idx, msize );
            block = new XMemBlock( idx, msize );
 79 _lsubPoolSize[idx]++;
            _lsubPoolSize[idx]++;
 80 if( _lsubPool[1][idx] )
            if( _lsubPool[1][idx] )
 81 _lsubPool[1][idx]->_pre = block;
                _lsubPool[1][idx]->_pre = block;
 82 block->_next = _lsubPool[1][idx];
            block->_next = _lsubPool[1][idx];
 83 _lsubPool[1][idx] = block;
            _lsubPool[1][idx] = block;
 84 return block;
            return block;
 85 }
        }
 86 }
    }
 87
 88 return (new XMemBlock( -1, size ));
     return (new XMemBlock( -1, size ));
 89 }
}
 90
 91 void XMemPool::free( XMemBlock *block )
void XMemPool::free( XMemBlock *block )
 92

 {
{
 93 if( block->_index < 0 )
    if( block->_index < 0 )
 94
 
     {
{
 95 delete block;
        delete block;
 96 return;
        return;
 97 }
    }
 98 if( block->_size <= S_MEM_THRE )
    if( block->_size <= S_MEM_THRE )
 99
 
     {
{
100 if( block->_next )
        if( block->_next )
101 block->_next->_pre = block->_pre;
            block->_next->_pre = block->_pre;
102 if( block->_pre )
        if( block->_pre )
103 block->_pre->_next = block->_next;
            block->_pre->_next = block->_next;
104 else if( !block->_next && !block->_pre )
        else if( !block->_next && !block->_pre )
105 _ssubPool[1][block->_index] = 0;
            _ssubPool[1][block->_index] = 0;
106 block->_next = _ssubPool[0][block->_index];
        block->_next = _ssubPool[0][block->_index];
107 if( _ssubPool[0][block->_index] )
        if( _ssubPool[0][block->_index] )
108 _ssubPool[0][block->_index]->_pre = block;
            _ssubPool[0][block->_index]->_pre = block;
109 _ssubPool[0][block->_index] = block;
        _ssubPool[0][block->_index] = block;
110 }
    }
111 else
    else
112
 
     {
{
113 if( block->_next )
        if( block->_next )
114 block->_next->_pre = block->_pre;
            block->_next->_pre = block->_pre;
115 if( block->_pre )
        if( block->_pre )
116 block->_pre->_next = block->_next;
            block->_pre->_next = block->_next;
117 else if( !block->_next && !block->_pre )
        else if( !block->_next && !block->_pre )
118 _lsubPool[1][block->_index] = 0;
            _lsubPool[1][block->_index] = 0;
119 block->_next = _lsubPool[0][block->_index];
        block->_next = _lsubPool[0][block->_index];
120 if( _lsubPool[0][block->_index] )
        if( _lsubPool[0][block->_index] )
121 _lsubPool[0][block->_index]->_pre = block;
            _lsubPool[0][block->_index]->_pre = block;
122 _lsubPool[0][block->_index] = block;
        _lsubPool[0][block->_index] = block;
123 }
    }
124 }
}
125
126 void XMemPool::destroy()
void XMemPool::destroy()
127

 {
{
128 for( int i = 0; i < _ssubPoolNum; i++ )
    for( int i = 0; i < _ssubPoolNum; i++ )
129
 
     {
{
130 XMemBlock *block = _ssubPool[0][i], *tmp;
        XMemBlock *block = _ssubPool[0][i], *tmp;
131 while( block )
        while( block )
132
 
         {
{
133 tmp = block->_next;
            tmp = block->_next;
134 delete block;
            delete block;
135 block = tmp;
            block = tmp;
136 }
        }
137 _ssubPool[0][i] = 0;
        _ssubPool[0][i] = 0;
138
139 block = _ssubPool[1][i];
        block = _ssubPool[1][i];
140 while( block )
        while( block )
141
 
         {
{
142 tmp = block->_next;
            tmp = block->_next;
143 delete block;
            delete block;
144 block = tmp;
            block = tmp;
145 }
        }
146 _ssubPool[1][i] = 0;
        _ssubPool[1][i] = 0;
147 _ssubPoolSize[i] = 0;
        _ssubPoolSize[i] = 0;
148 }
    }
149 for( int i = 0; i < _lsubPoolNum; i++ )
    for( int i = 0; i < _lsubPoolNum; i++ )
150
 
     {
{
151 XMemBlock *block = _lsubPool[0][i], *tmp;
        XMemBlock *block = _lsubPool[0][i], *tmp;
152 while( block )
        while( block )
153
 
         {
{
154 tmp = block->_next;
            tmp = block->_next;
155 delete block;
            delete block;
156 block = tmp;
            block = tmp;
157 }
        }
158 _lsubPool[0][i] = 0;
        _lsubPool[0][i] = 0;
159
160 block = _lsubPool[1][i];
        block = _lsubPool[1][i];
161 while( block )
        while( block )
162
 
         {
{
163 tmp = block->_next;
            tmp = block->_next;
164 delete block;
            delete block;
165 block = tmp;
            block = tmp;
166 }
        }
167 _lsubPool[1][i] = 0;
        _lsubPool[1][i] = 0;
168 _lsubPoolSize[i] = 0;
        _lsubPoolSize[i] = 0;
169 }
    }
170 }
}
171
172 XMemPool::~XMemPool()
XMemPool::~XMemPool()
173

 {
{
174 destroy();
    destroy();
175 delete []_ssubPoolSize;
    delete []_ssubPoolSize;
176 delete []_lsubPoolSize;
    delete []_lsubPoolSize;
177 delete []_ssubPool[0];
    delete []_ssubPool[0];
178 delete []_ssubPool[1];
    delete []_ssubPool[1];
179 delete []_lsubPool[0];
    delete []_lsubPool[0];
180 delete []_lsubPool[1];
    delete []_lsubPool[1];
181 }
} 
 
1 XMemPool samplePool(4096);
XMemPool samplePool(4096);
2 XMemBlock *sampleBlock = samplePool.alloc(sizeof(int)*100);
XMemBlock *sampleBlock = samplePool.alloc(sizeof(int)*100);
3 int *sampleData = sampleBlock->getMem<int>();
int *sampleData = sampleBlock->getMem<int>();
4 samplePool.free(sampleBlock);
samplePool.free(sampleBlock); 
很多细节还没考虑到,谁能为我推荐一个好的设计方案?双O(1)的