|
Object Pool Lite
Submitted by |
Here is an implementation of object pooling for c++ written with speed
(obviously) and minimal impact on existing code as the prime concerns. Thanks to
some friendly preprocessor macros, you can modify a class to use this pooling
with the addition of just two lines of code. For example, the class:
class pumpkin {
float radius, weight;
}; |
becomes:
class pumpkin {
POOLING_MEMBERS(pumpkin)
float radius, weight;
}; |
and somewhere in the .cpp file you need the line POOLING_FUNCTIONS(pumpkin) -
okay so there's three lines to add because you have to #include <object_pool.h>,
I was just seeing if you noticed...
The pool keeps an array of pointers to the type of object it is pooling, and an
index in this array. When an object pointer is requested, the index is
incremented and the pointer at that index is returned. When an object pointer is
deleted, the index is simply decremented. If all object pointers in the pool are
in use when another request occurs, the size of the pool is doubled (only one
call to 'new') before continuing as normal. There is no use of a linked list
because um... they generally call 'new' which is what we're trying to avoid. The
stack type storage means that a memory block can be allocated in amortized
constant time - here are some speed improvements measured (Redhat 6.1
P3-600MHz):
(Object size | Percent of standard allocation time taken)
1 byte 14%
36 bytes 13%
100 bytes 6%
1k bytes 1%Even allocation of one byte is quicker than standard allocation!
Pros:
Portable (tested with MSVC/Linux gcc)
O(1) allocation.
No preallocation, pool grows adaptively.
Small - here in its entirety on this page (below)
Cons:
Fixed size blocks means that separate pools are created even for objects which
may be of equal size and could have shared one pool.
No means of reducing the pool size when not in use.
#ifndef OBJECT_POOL_TEMPLATE
#define OBJECT_POOL_TEMPLATE
#include <vector
#define POOLING_MEMBERS(classname) \
public:\
static void* operator new(size_t size);\
static void operator delete(void* ptr, size_t size);\
static object_pool<classname m_pool;
#define POOLING_FUNCTIONS(classname) \
void* classname::operator new(size_t p_size) {\
return m_pool.newObject(p_size);\
}\
void classname::operator delete(void* p_ptr, size_t p_size) {\
m_pool.deleteObject(p_ptr, p_size);\
}\
object_pool<classname classname::m_pool;
template <class T class object_pool
{
private:
unsigned char ** m_freeBlocks;
size_t m_size;
long m_available;
std::vector<void* m_validHeapPtrs;
long m_bufferSize;
public:
object_pool()
{
m_size = sizeof(T);
m_available = 0;
m_bufferSize = 1;
m_freeBlocks = new unsigned char*[m_bufferSize];
unsigned char * t_ptr = new unsigned char[m_size*m_bufferSize];
m_validHeapPtrs.push_back(t_ptr);
m_freeBlocks[m_available++] = t_ptr;
};
~object_pool()
{
for (int i = 0; i < m_validHeapPtrs.size(); i++) {
::operator delete(m_validHeapPtrs[i]);
}
m_validHeapPtrs.clear();
::operator delete(m_freeBlocks);
}
void* newObject(size_t p_size)
{
if(p_size != m_size) {
return ::operator new(p_size);
} else if (m_available 0) {
return m_freeBlocks[--m_available];
} else {
::operator delete(m_freeBlocks);
m_freeBlocks = new unsigned char*[m_bufferSize*2];
unsigned char *t_ptr = new unsigned
char[m_size*m_bufferSize];
m_validHeapPtrs.push_back(t_ptr);
unsigned char *t_tp = t_ptr + m_size;
for (int i = 1; i < m_bufferSize; i++) {
m_freeBlocks[m_available++] = t_tp;
t_tp += m_size;
}
m_bufferSize *= 2;
return t_ptr;
}
}
void deleteObject(void* p_ptr, size_t p_size)
{
if(p_size != m_size){
::operator delete(p_ptr);
} else {
m_freeBlocks[m_available++] = (unsigned char*)p_ptr;
}
}
};
#endif |
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|