前言:阅读STL源码中内存池的实现,感触颇深,但又不知如何描述,STL源码剖析中已经描述的非常清楚了。所以这里我把其源码整理了一下,去除了多线程,方便阅读其实现原理。
头文件
内存池头文件
class MemoryPool {
private:
static size_t ROUND_UP(size_t bytes) {
return (((bytes) + 7) & ~(7));
}
union obj {
union obj * free_list_link;
char client_data[1];
};
private:
static obj * volatile free_list[16];
static size_t FREELIST_INDEX(size_t bytes) {
return (((bytes) + 7)/7);
}
static void *refill(size_t n);
static char *chunk_alloc(size_t size, int &nobjs);
// 分配状态
static char *start_free;
static char *end_free;
static size_t heap_size;
public:
//n必须大于0
static void * allocate(size_t n)
{
obj * volatile * my_free_list;
obj * result;
if (n > (size_t) 128) {
//只处理小于128的情况
return(::allocate(n));
}
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if (result == 0) {
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result -> free_list_link;
return (result);
};
/* p 不能为 0 */
static void deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj * volatile * my_free_list;
if (n > (size_t) 128) {
::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
q -> free_list_link = *my_free_list;
*my_free_list = q;
}
static void * reallocate(void *p, size_t old_sz, size_t new_sz);
} ;
其中在分配空间的时候用到了全局的分配函数,::deallocate(p, n);
和 ::allocate(n)
这在http://blog.csdn.net/z702143700/article/details/47166493这一节中给出。
实现
整个内存池的实现代码其实并不长,但是,不仔细研究是很难理解其中的奥秘,亲身体会,需要备注没有多少,研究源码是最好的解释。
char* MemoryPool::chunk_alloc(size_t size, int& nobjs)
{
char * result;
size_t total_bytes = size * nobjs;
size_t bytes_left = end_free - start_free;
if (bytes_left >= total_bytes) {
result = start_free;
start_free += total_bytes;
return(result);
} else if (bytes_left >= size) {
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return(result);
} else {
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
if (bytes_left > 0) {
obj * volatile * my_free_list =
free_list + FREELIST_INDEX(bytes_left);
((obj *)start_free) -> free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc(bytes_to_get);
if (0 == start_free) {
int i;
obj * volatile * my_free_list, *p;
for (i = size; i <= 128; i += 8) {
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if (0 != p) {
*my_free_list = p -> free_list_link;
start_free = (char *)p;
end_free = start_free + i;
return(chunk_alloc(size, nobjs));
}
}
end_free = 0;
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
}
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return(chunk_alloc(size, nobjs));
}
}
void* MemoryPool::refill(size_t n)
{
int nobjs = 20;
char * chunk = chunk_alloc(n, nobjs);
obj * volatile * my_free_list;
obj * result;
obj * current_obj, * next_obj;
int i;
if (1 == nobjs) return(chunk);
my_free_list = free_list + FREELIST_INDEX(n);
result = (obj *)chunk;
*my_free_list = next_obj = (obj *)(chunk + n);
for (i = 1; ; i++) {
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - 1 == i) {
current_obj -> free_list_link = 0;
break;
} else {
current_obj -> free_list_link = next_obj;
}
}
return(result);
}
void* MemoryPool::reallocate(void *p,size_t old_sz,size_t new_sz)
{
void * result;
size_t copy_sz;
if (old_sz > 128 && new_sz > 128) {
return(realloc(p, new_sz));
}
if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p);
result = allocate(new_sz);
copy_sz = new_sz > old_sz? old_sz : new_sz;
memcpy(result, p, copy_sz);
deallocate(p, old_sz);
return(result);
}
char *MemoryPool::start_free = 0;
char *MemoryPool::end_free = 0;
size_t MemoryPool::heap_size = 0;
MemoryPool::obj * volatile free_list[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
总结:在写内存池实现技术的时候,我参考很多了博主写的玩具内存吹实现,但是跟STL这个小型高效的内存池比起来还是相差很远很远的。