Introduction of a fixed size memory pool with a typical free list implementation

+ : amortized O(1) allocation, O(1) deallocation, less overhead per allocation
- : unused memory is not reclaimed until death or manual invocation of a function

svn-id: r31320
This commit is contained in:
Bertrand Augereau 2008-03-30 05:42:39 +00:00
parent dc813c1c20
commit 411a588850
3 changed files with 129 additions and 0 deletions

94
common/memorypool.cpp Normal file
View file

@ -0,0 +1,94 @@
#include "common/memorypool.h"
#include <algorithm>
namespace Common
{
static const size_t CHUNK_PAGE_SIZE = 32;
void* MemoryPool::allocPage() {
void* result = ::malloc(CHUNK_PAGE_SIZE * _chunkSize);
_pages.push_back(result);
void* current = result;
for(size_t i=1; i<CHUNK_PAGE_SIZE; ++i)
{
void* next = ((char*)current + _chunkSize);
*(void**)current = next;
current = next;
}
*(void**)current = NULL;
return result;
}
MemoryPool::MemoryPool(size_t chunkSize) {
// You must at least fit the pointer in the node (technically unneeded considering the next rounding statement)
_chunkSize = std::max(chunkSize, sizeof(void*));
// There might be an alignment problem on some platforms when trying to load a void* on a non natural boundary
// so we round to the next sizeof(void*)
_chunkSize = (_chunkSize + sizeof(void*) - 1) & (~(sizeof(void*) - 1));
_next = NULL;
}
MemoryPool::~MemoryPool() {
for(size_t i=0; i<_pages.size(); ++i)
free(_pages[i]);
}
void* MemoryPool::malloc() {
#if 1
if(!_next)
_next = allocPage();
void* result = _next;
_next = *(void**)result;
return result;
#else
return ::malloc(_chunkSize);
#endif
}
void MemoryPool::free(void* ptr) {
#if 1
*(void**)ptr = _next;
_next = ptr;
#else
::free(ptr);
#endif
}
// Technically not compliant C++ to compare unrelated pointers. In practice...
bool MemoryPool::isPointerInPage(void* ptr, void* page) {
return (ptr >= page) && (ptr < (char*)page + CHUNK_PAGE_SIZE * _chunkSize);
}
void MemoryPool::freeUnusedPages() {
//std::sort(_pages.begin(), _pages.end());
Array<int> numberOfFreeChunksPerPage;
numberOfFreeChunksPerPage.resize(_pages.size());
for(size_t i=0; i<numberOfFreeChunksPerPage.size(); ++i) {
numberOfFreeChunksPerPage[i] = 0;
}
void* iterator = _next;
while(iterator) {
// This should be a binary search
for(size_t i=0; i<_pages.size(); ++i) {
if(isPointerInPage(iterator, _pages[i])) {
++numberOfFreeChunksPerPage[i];
break;
}
}
iterator = *(void**)iterator;
}
for(size_t i=0; i<_pages.size(); ++i) {
if(numberOfFreeChunksPerPage[i] == CHUNK_PAGE_SIZE) {
free(_pages[i]);
_pages[i] = NULL; // TODO : Remove NULL values
}
}
}
}

34
common/memorypool.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef COMMON_MEMORYPOOL_H
#define COMMON_MEMORYPOOL_H
#include <cstring>
#include "common/array.h"
namespace Common
{
class MemoryPool
{
private:
MemoryPool(const MemoryPool&);
MemoryPool& operator=(const MemoryPool&);
size_t _chunkSize;
Array<void*> _pages;
void* _next;
void* allocPage();
bool isPointerInPage(void* ptr, void* page);
public:
MemoryPool(size_t chunkSize);
~MemoryPool();
void* malloc();
void free(void* ptr);
void freeUnusedPages();
};
}
#endif

View file

@ -7,6 +7,7 @@ MODULE_OBJS := \
file.o \
fs.o \
hashmap.o \
memorypool.o \
md5.o \
mutex.o \
str.o \