Implement memory allocator and deallocator using the mechanism in SGI STL
来源:互联网 发布:网络胜利组 百度网盘 编辑:程序博客网 时间:2024/06/09 17:14
STL is an amazing utility related to C++. In most cases, the vectors and algorithms can work very well, i.e., effectively and efficiently. The management of memory, allocation and deallocation, is well designed to achieve that goal. In this article, an implementation of memory allocator and deallocator, which is based on the mechanism used in SGI STL, is given. Following the code, you will understand how it works.
There are two kinds of allocators, one dealing with large block allocation, the other dealing with small block allocation. And, one tricky thing is that they both use malloc, realloc and free, which are in C library, to do the real memory allocation. The reason is that it is more direct and more efficient. The following code shows the mechanism behind them (in SGI STL, the whole process is arranged in hierarchical function calls which are more clear, while here, in order to show it as a whole, sort of design philosophy, I combined them together).
//my_allocator.h
#define _MY_ALLOCATOR_H_
#include <cstddef>
// oom: out of memory
typedef void (*oom_handler)(void);
class MallocAllocator {
public:
static void * Allocate(size_t);
static void Deallocate(void *, size_t);
// old returned
static oom_handler GetOOMHandler();
// new set, old returned
static oom_handler SetOOMHandler(oom_handler);
private:
//size_t blk_size;
static oom_handler malloc_allocator_oom_handler;
};
enum { _ALIGN = 8 };
enum { _MAX_BYTES = 128 };
enum { _FREELISTS_NUMBER = 16 };
enum { _BLOCK_NUMBER = 20 };
class DefaultAllocator {
public:
static void * Allocate(size_t);
static void Deallocate(void *, size_t);
private:
union obj {
union obj * next; // node in free list
char data[1]; // real data
};
// round the size up to the ceiling multiple of 8
static size_t RoundUp(size_t);
// find the appropriate free list for the given size
static size_t FreelistIndex(size_t);
// fill a new free list
static obj * FillFreelist(size_t);
// allocate a new memory block
static char * AllocateBlock(size_t, size_t &);
// manage all the free lists
static obj * volatile _freelists[_FREELISTS_NUMBER];
static char * _pool_start; // start of the memory pool
static char * _pool_end; // end of the memory pool
static size_t _pool_size; // size of the memory pool
};
#endif
//my_allocator.cpp
#include <cstdlib>
#include <new>
#include <iostream>
using namespace std;
// class MallocAllocator
oom_handler MallocAllocator::malloc_allocator_oom_handler = 0;
void * MallocAllocator::Allocate(size_t size) {
void * result = malloc(size);
// deal with the condition of out of memory
if(result == 0) {
oom_handler current_handler;
// infinite loop
while(1) {
current_handler = GetOOMHandler();
if(current_handler == 0)
throw std::bad_alloc(); // no oom handler
else {
// do something, e.g., throw an exception, or free some space, or set a new oom_handler
(*current_handler)();
// try to allocate again
result = malloc(size);
if(result != 0)
return result;
}
}
}
else
return result;
}
void MallocAllocator::Deallocate(void * dead_obj, size_t size) {
free(dead_obj);
}
oom_handler MallocAllocator::GetOOMHandler() {
return malloc_allocator_oom_handler;
}
oom_handler MallocAllocator::SetOOMHandler(oom_handler new_oom_handler) {
oom_handler old_oom_handler = malloc_allocator_oom_handler;
malloc_allocator_oom_handler = new_oom_handler;
return old_oom_handler;
}
// end of MallocAllocator
// class DefaultAllocator
char * DefaultAllocator::_pool_start = 0;
char * DefaultAllocator::_pool_end = 0;
size_t DefaultAllocator::_pool_size = 0;
DefaultAllocator::obj * volatile DefaultAllocator::_freelists[_FREELISTS_NUMBER] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
size_t DefaultAllocator::RoundUp(size_t size) {
// if size is already a multiple of _ALIGN, it will not change
return (size + _ALIGN - 1) & ~(_ALIGN - 1);
}
size_t DefaultAllocator::FreelistIndex(size_t size) {
// size will never be zero
return (size + _ALIGN - 1) / _ALIGN - 1;
}
void * DefaultAllocator::Allocate(size_t size) {
// deal with large memory block request
if(size > _MAX_BYTES)
return MallocAllocator::Allocate(size);
// deal with small memory block request
size_t blk_size = RoundUp(size);
size_t list_index = FreelistIndex(blk_size);
obj * list_head = _freelists[list_index];
obj * result;
// the free list is not empty
if(list_head != 0) {
result = list_head;
cout << "list_head: " << list_head << ", next: " << list_head->next << endl;
_freelists[list_index] = list_head->next;
cout << "list_head: " << list_head << ", next: " << list_head->next << endl;
//return list_head;
}
// fill a new free list
else {
//cout << "1" << endl;
size_t blk_num = _BLOCK_NUMBER;
// check the pool
size_t free_size = _pool_end - _pool_start;
size_t request_size = blk_num * blk_size;
// pool is enough for at least 1 block
if(free_size >= blk_size) {
char * chunk = _pool_start;
// pool is enough for more than BLOCK_NUMBER blocks
if(request_size <= free_size) {
_pool_start += request_size;
}
// pool is less than BLOCK_NUMBER blocks
else {
blk_num = free_size / blk_size;
_pool_start += blk_num * blk_size;
}
// if at least 2 blocks, link them together
if(blk_num > 1) {
obj * next_obj, * curr_obj;
next_obj = /*static_cast<obj *>*/(obj *)(chunk + blk_size);
//cout << "head: " << next_obj << endl; //10 //correct
for(int i = 1; i < blk_num - 1; ++i) {
curr_obj = next_obj;
//next_obj = static_cast<obj *>(static_cast<char *>(next_obj) + blk_size);
next_obj = (obj *)((char *)(next_obj) + blk_size);
curr_obj->next = next_obj;
//cout << "head: " << next_obj << endl; //correct
}
next_obj->next = 0;
//_freelists[list_index] = static_cast<obj *>(chunk + blk_size);
_freelists[list_index] = (obj *)(chunk + blk_size);
//cout << "haha: " << _freelists[list_index] << endl;
}
//result = static_cast<obj *>(chunk);
result = (obj *)(chunk);
}
// pool is less than 1 block
else {
// put the fragment into the appropriate free list
if(free_size > 0) {
int index = FreelistIndex(free_size);
//(static_cast<obj *>(_pool_start))->next = _freelists[index];
((obj *)_pool_start)->next = _freelists[index];
//_freelists[index] = static_cast<obj *>(_pool_start);
_freelists[index] = (obj *)_pool_start;
}
// allocate new pool
request_size = (request_size << 1) + RoundUp((_pool_end - _pool_start) >> 4);
_pool_start = static_cast<char *>(malloc(request_size));
if(_pool_start != 0) {
_pool_end = _pool_start + request_size;
//cout << "_pool_start: " << (void *)_pool_start << endl;
return Allocate(size);
}
else {
// check the existing free lists which are large enough
for(int i = list_index + 1; i < _FREELISTS_NUMBER; ++i) {
if(_freelists[i] != 0) {
//_pool_start = static_cast<char *>(_freelists[i]);
_pool_start = (char *)(_freelists[i]);
//_pool_end = static_cast<char *>(_freelists[i]) + i * _ALIGN;
_pool_end = (char *)(_freelists[i]) + i * _ALIGN;
_freelists[i] = _freelists[i]->next;
return Allocate(size);
}
}
}
_pool_end = 0;
_pool_start = static_cast<char *>(MallocAllocator::Allocate(request_size));
_pool_end = _pool_start + request_size;
return Allocate(size);
}
}
return result;
}
void DefaultAllocator::Deallocate(void * dead, size_t size) {
// deal with large memory block
if(size > _MAX_BYTES)
MallocAllocator::Deallocate(dead, size);
// deal with small memory block
size_t index = FreelistIndex(size);
obj * freelist = _freelists[index];
((obj *)dead)->next = freelist;
_freelists[index] = (obj *)dead;
}
// end of DefaultAllocator
These two classes are wrappered by a class MemoryPool.
//MemoryPool.h
#define _MEMORY_POOL_H
#include <cstddef>
#include "my_allocator.h"
class MemoryPool {
public:
MemoryPool(size_t);
~MemoryPool();
void * Alloc(size_t);
void Free(void *, size_t);
public:
size_t obj_size, block_size;
};
#endif
//MemoryPool.cpp
#include <iostream>
using namespace std;
MemoryPool::MemoryPool(size_t size)
: obj_size(size), block_size(16)
{}
MemoryPool::~MemoryPool() {}
void * MemoryPool::Alloc(size_t size) {
DefaultAllocator::Allocate(size);
}
void MemoryPool::Free(void * dead_object, size_t size) {
if(dead_object == 0)
return;
DefaultAllocator::Deallocate(dead_object, size);
}
AirplaneWithPool is a small class sized 4 bytes for testing.
//AirplaneWithPool.h
#define _AIRPLANE_WITH_POOL_H
#include "MemoryPool.h"
#include <cstddef>
class AirplaneReq {
//many data and function members
};
class AirplaneWithPool {
public:
static void * operator new(size_t);
static void operator delete(void *, size_t);
public:
AirplaneReq * req;
static MemoryPool mem_pool;
};
#endif
//AirplaneWithPool.cpp
#include "MemoryPool.h"
MemoryPool AirplaneWithPool::mem_pool(sizeof(AirplaneWithPool));
void * AirplaneWithPool::operator new(size_t size) {
return mem_pool.Alloc(size);
}
void AirplaneWithPool::operator delete(void * dead_object, size_t size) {
mem_pool.Free(dead_object, size);
}
Now is the tesing code.
//main.cpp
#include <iostream>
using namespace std;
int main() {
AirplaneWithPool * apwp0 = new AirplaneWithPool();
cout << "apwp0: " << apwp0 << endl;
AirplaneWithPool * apwp1 = new AirplaneWithPool();
cout << "apwp1: " << apwp1 << endl;
AirplaneWithPool * apwp2 = new AirplaneWithPool();
cout << "apwp2: " << apwp2 << endl;
delete apwp1;
AirplaneWithPool * apwp3 = new AirplaneWithPool();
cout << "apwp3: " << apwp3 << endl;
delete apwp3;
AirplaneWithPool * apwp4 = new AirplaneWithPool();
cout << "apwp4: " << apwp4 << endl;
return 0;
}
The running results are as follows.
//printed in terminal
apwp0: 0x804b008
apwp1: 0x804b010
apwp2: 0x804b018
apwp3: 0x804b010
apwp4: 0x804b010
We can see every object ocupies 8 bytes although the real size of it is only 4 bytes. The reason is in SGI STL, the size of requested block is always rounded up to a multiple of 8 in bytes.
- Implement memory allocator and deallocator using the mechanism in SGI STL
- A wrapper of SGI STL memory allocator and deallocator
- Memory management: default new & delete vs. allocator & deallocator using a pool
- pool memory allocate in SGI STL
- sgi-stl,allocator/boost:pool
- SGI STL (5) :: Allocator Design
- Implement Interface Mechanism Using Templates
- SGI-STL学习笔记之allocator
- SGI-STL学习笔记之allocator .
- SGI STL 源码解读之Allocator
- SGI STL内存配置器Allocator
- 【STL】SGI空间配置器 Allocator
- The mechanism and implementation of detecting memory leak
- The Android ION memory allocator
- The Android ION memory allocator
- The Android ION memory allocator
- The Android ION memory allocator
- The Android ION memory allocator
- VS2008正式版下载-vs2008下载地址
- 一个用JAVA写的清除EXE病毒文件的程序(转)
- ADO.NET 2.0对象模型
- 巨人网络宣布与华为建立研发合作伙伴关系
- 微软最走运/倒霉的十个瞬间
- Implement memory allocator and deallocator using the mechanism in SGI STL
- 2007年下半年国家软考指定教材
- 欧洲最大IT展会CeBIT开幕 绿色IT是主题
- NetBeans IDE 6.1 Beta Now Available!
- 2007年 上半年信息系统监理师 下午试卷
- 微软2008年产品列表
- On shrinking table sizes
- 2007年 上半年信息系统监理师 上午试卷
- doc