内存管理边界标识首次拟合c++实现,持续更新中。。。
///
/// Copyright (c) 2014 xseekerj, All Rights Reserved.
///
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <mutex>
#define nullptr 0
inline int rrand(int min, int max)
{
return ( rand() % ((max) - (min)) + (min) );
}
/*
* size in bytes constant: SZ Definition
*/
#ifndef _POL_SZ
#define _POL_SZ
static const uint64_t __B__ = (1);
static const uint64_t __KB__ = (1024 * __B__) ;
static const uint64_t __MB__ = (1024 * __KB__);
static const uint64_t __GB__ = (1024 * __MB__);
static const uint64_t __TB__ = (1024 * __GB__);
static const uint64_t __PB__ = (1024 * __TB__);
static const uint64_t __EB__ = (1024 * __PB__);
#define __b__ __B__
#define __k__ __K__
#define __m__ __M__
#define __g__ __G__
#define __t__ __T__
#define __e__ __E__
#define __K__ __KB__
#define __M__ __MB__
#define __G__ __GB__
#define __T__ __TB__
#define __P__ __PB__
#define __E__ __EB__
#define SZ(n, u) ( (n) * __##u##__ )
static const uint8_t __MAX_UINT8 = SZ(256, B) - 1;
static const uint16_t __MAX_UINT16 = SZ(64, KB) - 1;
static const uint32_t __MAX_UINT32 = SZ(4, GB) - 1;
static const uint64_t __MAX_UINT64 = SZ(15, EB) + (SZ(1, EB) - 1);
#endif /* _POL_SZ */
#define sz_align(d,a) (((d) + (a - 1)) & ~(a - 1))
// #define EANBLE_MULTI_THREAD 1
class mempool
{
struct memblock_head_t
{
memblock_head_t* prev;
memblock_head_t* next;
size_t size;
bool unused;
};
struct memblock_foot_t
{
memblock_head_t* uplink;
};
static const size_t reserved_size = sizeof(memblock_head_t) + sizeof(memblock_foot_t);
static const size_t min_size = sizeof(void*) * 2;
static const size_t min_block_size = reserved_size + min_size;
#define FOOT_LOC(h) ((memblock_foot_t*)( (char*)h + h->size - sizeof(memblock_foot_t) ) )
#define HEAD_LOC(pu) ( (memblock_head_t*)( (char*)pu - sizeof(memblock_head_t) ) )
#define UPDATE_FOOT(h) ( FOOT_LOC(h)->uplink = h )
#define LEFT_FOOT_LOC(h) ( (memblock_foot_t*)( (char*)h - sizeof(memblock_foot_t) ) )
#define RIGHT_HEAD_LOC(h) ( (memblock_head_t*)( (char*)h + h->size ) )
#define REMAIN_SIZE(blk,n) (blk->size - reserved_size - (n) ) // calculate remain size after n bytes allocated.
public:
mempool(size_t size = SZ(64, k))
{
init(size);
}
~mempool(void)
{
free(memory_);
}
void init(size_t size)
{
size = sz_align(size, SZ(64, k));
memory_ = malloc(size);
memblock_head_t* header = (memblock_head_t*)(memory_);
header->size = size;
header->unused = true;
header->prev = header;
header->next = header;
this->freelist_ = FOOT_LOC(header)->uplink = header;
this->memory_size_ = size;
}
void* allocate(size_t size)
{
#ifdef EANBLE_MULTI_THREAD
std::unique_lock<std::mutex> guard(this->mtx_);
#endif
size_t n = sz_align(size, min_size);
memblock_head_t* blk = freelist_;
for(; blk != nullptr &&
blk->size - reserved_size < n &&
blk->next != freelist_; blk = blk->next){;}
if(blk == nullptr || blk->size - reserved_size < n) {
return malloc(size);
}
else {
blk->unused = false;
char* p = (char*)blk + sizeof(memblock_head_t);
if( REMAIN_SIZE(blk, n) < min_block_size ) /* can't construct the new memory block to respond any alloc request. */
{
// blk->size =
if(blk == freelist_) {
freelist_ = nullptr;
}
else {
freelist_->prev = blk->next; blk->next->prev = freelist_;
}
}
else {
/* remain block */
memblock_head_t* reblock = (memblock_head_t*)(p + n + sizeof(memblock_foot_t));
reblock->unused = true;
reblock->size = (char*)blk + blk->size - (char*)reblock;
UPDATE_FOOT(reblock);
blk->size = (char*)reblock - (char*)blk;
UPDATE_FOOT(blk);
if(blk->next == blk)
{ // self
blk->next = reblock;
blk->prev = reblock;
reblock->prev = blk;
reblock->next = blk;
}
else { // insert
reblock->prev = blk;
reblock->next = blk->next;
blk->next->prev = reblock;
blk->next = reblock;
// ptr->prev = reblock;
}
freelist_ = reblock;
}
return p;
}
}
void deallocte(void* pUserData)
{
if(!belong_to(pUserData))
{
free(pUserData);
return;
}
#ifdef EANBLE_MULTI_THREAD
std::unique_lock<std::mutex> guard(this->mtx_);
#endif
memblock_head_t* curh = HEAD_LOC(pUserData);
memblock_foot_t* lf = LEFT_FOOT_LOC(curh);
memblock_head_t* rh = RIGHT_HEAD_LOC(curh);
bool vlf = is_valid_leftf(lf);
bool vrh = is_valid_righth(rh);
#ifdef _DEBUG
memset(pUserData, 0x0, curh->size - reserved_size);
#endif
if( ( vlf && lf->uplink->unused ) && (!vrh || !rh->unused) )
{ // merge curret to left block
lf->uplink->next = curh->next;
if(curh->next != nullptr)
curh->next->prev = lf->uplink;
lf->uplink->size += curh->size;
UPDATE_FOOT(lf->uplink);
this->freelist_ = lf->uplink;
}
else if( (vrh && rh->unused) && (!vlf || !lf->uplink->unused ) )
{ // merge right to current block
curh->unused = true;
curh->next = rh->next;
if(rh->next != nullptr)
rh->next->prev = curh;
curh->size += rh->size;
UPDATE_FOOT(curh);
this->freelist_ = curh;
}
else if( (vlf && lf->uplink->unused) && (vrh && rh->unused) )
{ // merge current and right to left block
lf->uplink->next = rh->next;
if(rh->next != nullptr)
rh->next->prev = lf->uplink;
lf->uplink->size += (curh->size + rh->size);
UPDATE_FOOT(lf->uplink);
this->freelist_ = lf->uplink;
}
else {
// no need merge
curh->unused = true;
this->freelist_ = curh;
}
}
bool belong_to(void* p)
{
return p >= this->memory_ && p < ( (char*)this->memory_ + this->memory_size_ );
}
bool is_valid_leftf(void* lf)
{
return ((char*)lf > ( (char*)this->memory_ + sizeof(memblock_head_t)) );
}
bool is_valid_righth(void* rh)
{
return (char*)rh < ((char*)this->memory_ + memory_size_ - sizeof(memblock_foot_t) );
}
private:
void* memory_;
size_t memory_size_; // memory total size;
memblock_head_t* freelist_;
#ifdef EANBLE_MULTI_THREAD
std::mutex mtx_;
#endif
};
int main(int argc, char** argv)
{
/*apr_allocator_t* allocator;
apr_allocator_create(&allocator);
apr_memnode_t* node = apr_allocator_alloc(allocator, SZ(3, k));
apr_allocator_free(allocator, node);
node = apr_allocator_alloc(allocator, SZ(3, k));*/
int times = 1000000;
mempool pool;
char* p1 = (char*)pool.allocate(25);
strcpy(p1, "hello world");
char* p2 = (char*)pool.allocate(25);
char* p3 = (char*)pool.allocate(25);
char* p4 = (char*)pool.allocate(25);
pool.deallocte(p2);
pool.deallocte(p4);
pool.deallocte(p3);
pool.deallocte(p1);
double end[4];
clock_t start = clock();
for(int i = 0; i < times; ++i)
{
void* p = malloc(rrand(sizeof(int), 8192 * 2));
if(p)
free(p);
}
end[0] = (clock() - start) / (double)CLOCKS_PER_SEC;
start = clock();
for(int i = 0; i < times; ++i)
{
void* p = pool.allocate(rrand(sizeof(int), 8192 * 2));
if(p)
pool.deallocte(p);
}
end[1] = (clock() - start) / (double)CLOCKS_PER_SEC;
start = clock();
for(int i = 0; i < times; ++i)
{
void* p = malloc(sizeof(int));
if(p)
free(p);
}
end[2] = (clock() - start) / (double)CLOCKS_PER_SEC;
/*start = clock();
for(int i = 0; i < times; ++i)
{
apr_memnode_t* p = apr_allocator_alloc(allocator, rrand(sizeof(int), 8192 * 2));
if(p)
apr_allocator_free(allocator, p);
}
end[3] = (clock() - start) / (double)CLOCKS_PER_SEC;*/
printf("malloc/free random size %d times, use %lf seconds\n", times, end[0]);
printf("mempool allocate/deallocte random size %d times, use %lf seconds\n", times, end[1]);
printf("malloc/free fixed size %d times, use %lf seconds\n", times, end[2]);
//printf("apr alloc/free random size %d times, use %lf seconds\n", times, end[3]);
/* result at win32 release:
malloc/free random size 1000000 times, use 7.251000 seconds
mempool allocate/deallocte random size 1000000 times, use 0.031000 seconds
malloc/free fixed size 1000000 times, use 0.360000 seconds
apr alloc/free random size 1000000 times, use 0.031000 seconds
*/
/* result at linux release
malloc/free random size 1000000 times, use 0.070000 seconds
mempool allocate/deallocte random size 1000000 times, use 0.030000 seconds
malloc/free fixed size 1000000 times, use 0.040000 seconds
apr alloc/free random size 1000000 times, use 0.040000 seconds
*/
#ifdef _WIN32
system("pause");
#endif
return 0;
}
以下是结合固定大小内存快实现的内存池管理
// mempool2.h: a simple mempool implementation
#ifndef _MEMPOOL2_H_
#define _MEMPOOL2_H_
#ifndef _POLITE_SZ_ALIGN
#define _POLITE_SZ_ALIGN
#define sz_align(d,a) (((d) + ((a) - 1)) & ~((a) - 1))
// #define sz_align(x,n) ( (x) + ( (n) - (x) % (n) ) - ( ( (x) % (n) == 0 ) * (n) ) )
#endif
/*
* _POL_CONSTANTS_ Definitions
*/
#ifndef _POL_CONSTANTS
#define _POL_CONSTANTS
static const uint64_t __B__ = (1);
static const uint64_t __KB__ = (1024 * __B__) ;
static const uint64_t __MB__ = (1024 * __KB__);
static const uint64_t __GB__ = (1024 * __MB__);
static const uint64_t __TB__ = (1024 * __GB__);
static const uint64_t __PB__ = (1024 * __TB__);
static const uint64_t __EB__ = (1024 * __PB__);
#endif /* _POL_CONSTANTS */
#include <memory>
/*
* TEMPLATE TYPE structs Definition
*/
#ifndef _POL_BOOL
#define _POL_BOOL
template<typename _Int>
struct Bool
{
typedef _Int type;
static const type True = ~0;
static const type False = 0;
} ;
#endif /* _POL_BOOL */
/*
* size in bytes constant: SZ Definition
*/
#ifndef _POL_SZ
#define _POL_SZ
#define __b__ __B__
#define __k__ __K__
#define __m__ __M__
#define __g__ __G__
#define __t__ __T__
#define __e__ __E__
#define __K__ __KB__
#define __M__ __MB__
#define __G__ __GB__
#define __T__ __TB__
#define __P__ __PB__
#define __E__ __EB__
#define SZ(n, u) ( (n) * __##u##__ )
static const uint8_t __MAX_UINT8 = SZ(256, B) - 1;
static const uint16_t __MAX_UINT16 = SZ(64, KB) - 1;
static const uint32_t __MAX_UINT32 = SZ(4, GB) - 1;
static const uint64_t __MAX_UINT64 = SZ(15, EB) + (SZ(1, EB) - 1);
#endif /* _POL_SZ */
#include <assert.h>
#include <stdint.h>
namespace thelib {
namespace gc {
class object_pool2
{
typedef struct free_link_node
{
free_link_node* next;
} *free_link;
typedef struct chunk_link_node
{
chunk_link_node* next; /* at start of data */
char data[0];
} *chunk_link;
object_pool2(const object_pool2&);
void operator= (const object_pool2&);
public:
object_pool2(size_t elemsize, size_t elemcount) : _Myhead(nullptr), _Mychunk(nullptr), _Mycount(0), _MyElemSize(elemsize), _MyElemCount(elemcount)
{
this->_Enlarge();
}
~object_pool2(void)
{
this->purge();
}
void cleanup(void)
{
if(this->_Mychunk = nullptr) {
return;
}
free_link_node* prev = nullptr;
chunk_link_node* chunk = this->_Mychunk;
for (; chunk != nullptr; chunk = chunk->next)
{
char* begin = chunk->data;
char* rbegin = begin + (_MyElemCount - 1) * _MyElemSize;
if(prev != nullptr)
prev->next = reinterpret_cast<free_link>(begin);
for (char* ptr = begin; ptr < rbegin; ptr += _MyElemSize )
{
reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + _MyElemSize);
}
prev = reinterpret_cast <free_link_node*>(rbegin);
}
this->_Myhead = reinterpret_cast<free_link_node*>(this->_Mychunk->data);
this->_Mycount = 0;
}
void purge(void)
{
chunk_link_node* ptr = this->_Mychunk;
while (ptr != nullptr)
{
chunk_link_node* deleting = ptr;
ptr = ptr->next;
free(deleting);
}
_Myhead = nullptr;
_Mychunk = nullptr;
_Mycount = 0;
}
size_t count(void) const
{
return _Mycount;
}
// if the type is not pod, you may be use placement new to call the constructor,
// for example: _Ty* obj = new(pool.get()) _Ty(arg1,arg2,...);
void* get(void)
{
if (nullptr == this->_Myhead)
{
this->_Enlarge();
}
free_link_node* ptr = this->_Myhead;
this->_Myhead = ptr->next;
++_Mycount;
return reinterpret_cast<void*>(ptr);
}
void release(void* _Ptr)
{
free_link_node* ptr = reinterpret_cast<free_link_node*>(_Ptr);
ptr->next = this->_Myhead;
this->_Myhead = ptr;
--_Mycount;
}
private:
void _Enlarge(void)
{
// static_assert(_ElemCount > 0, "Invalid Element Count");
chunk_link new_chunk = (chunk_link)malloc(sizeof(chunk_link_node) + _MyElemCount * _MyElemSize);
if(new_chunk == nullptr)
return;
#ifdef _DEBUG
::memset(new_chunk, 0x00, sizeof(chunk_link_node) + _MyElemCount * _MyElemSize);
#endif
new_chunk->next = this->_Mychunk;
this->_Mychunk = new_chunk;
char* begin = this->_Mychunk->data;
char* rbegin = begin + (_MyElemCount - 1) * _MyElemSize;
for (char* ptr = begin; ptr < rbegin; ptr += _MyElemSize )
{
reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + _MyElemSize);
}
reinterpret_cast <free_link_node*>(rbegin)->next = nullptr;
this->_Myhead = reinterpret_cast<free_link_node*>(begin);
}
private:
free_link _Myhead; // link to free head
chunk_link _Mychunk; // chunk link
size_t _Mycount; // allocated count
const size_t _MyElemSize; // elem size
const size_t _MyElemCount; // elem count
}; /* equalize size block */
#ifndef _INLINE_ASM_BSR
#define _INLINE_ASM_BSR
#ifdef _WIN32
#pragma intrinsic(_BitScanReverse)
#define BSR(_Index, _Mask) _BitScanReverse((unsigned long*)&_Index, _Mask);
#else
#define BSR(_Index,_Mask) __asm__ __volatile__("bsrl %1, %%eax\n\tmovl %%eax, %0":"=r"(_Index):"r"(_Mask):"eax")
#endif
#endif
class mempool2
{
static const size_t MAX_INDEX = 11;
static const size_t BOUNDARY_INDEX = 5 + sizeof(void*) / 8; // 5 at x86_32, 6 at x86_64
static const size_t BOUNDARY_SIZE = (1 << BOUNDARY_INDEX); // 32bytes at x86_32, 64bytes at x86_64
public:
mempool2(void)
{
init();
}
~mempool2(void)
{
for(size_t index = 0; index <= MAX_INDEX; ++index)
{
delete blocks[index];
}
}
void* allocate(size_t in_size)
{
uint32_t size = sz_align(in_size + sizeof(uint32_t), BOUNDARY_SIZE);
uint32_t index = 0;
BSR(index, size >> BOUNDARY_INDEX);
index += (bool)((size-1) & size); // adjust index
void* raw = nullptr;
if(index <= MAX_INDEX)
{
raw = this->blocks[index]->get();
}
else {
raw = malloc(size);
}
if(raw != nullptr) {
*reinterpret_cast<uint32_t*>(raw) = size;
return (char*)raw + sizeof(uint32_t);
}
return nullptr;
}
void deallocate(void* p)
{
char* raw = (char*)p - sizeof(uint32_t);
uint32_t size = *reinterpret_cast<uint32_t*>( raw );
uint32_t index = 0;
BSR(index, size >> BOUNDARY_INDEX);
index += (bool)((size-1) & size); // adjust index
if(index <= MAX_INDEX) {
this->blocks[index]->release(raw);
return;
}
free(raw);
}
private:
void init(void)
{
for(size_t index = 0; index <= MAX_INDEX; ++index)
{
size_t elem_size = BOUNDARY_SIZE << index;
blocks[index] = new object_pool2(elem_size, SZ(512,k) / elem_size);
}
}
object_pool2* blocks[MAX_INDEX + 1];
}; // namespace: thelib::gc::mempool2
}; // namespace: thelib::gc
}; // namespace: thelib
#endif
/*
* Copyright (c) 2014 by X.D. Guo ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
**/