http://blog.chinaunix.net/uid-24690947-id-3059622.html
原文有一点小错误
以下是改正的
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#define __ALIGN 8 //小型区块上调边界
#define __MAX_BYTES 128 //小型区块大小的上限
#define __NFREELISTS (__MAX_BYTES/__ALIGN) //free-lists的个数
typedef union obj{
union obj *free_list_link;
char client_data[1];
}obj;
obj *free_list[__NFREELISTS];
char *start_free; //mempool开始位置
char *end_free; //mempool结束位置
size_t heapsize;
size_t ROUND_UP(size_t bytes);
size_t FREELIST_INDEX(size_t bytes);
void *stl_malloc(size_t nbytes);
void stl_free(void *p, size_t nbytes);
void *refill(size_t n);
char *chunk_alloc(size_t bytes, size_t *nobjs);
int main(){
int len= 65;
void *ptr = stl_malloc(len);
printf("%p\n", ptr);
stl_free(ptr, len);
return 0;
}
//将bytes上调到__ALIGN的倍数
size_t ROUND_UP(size_t bytes){
return ((bytes + __ALIGN - 1) & ~(__ALIGN - 1));
}
//返回bytes所对应的freelist索引号
size_t FREELIST_INDEX(size_t bytes){
return ((bytes + __ALIGN - 1) / __ALIGN - 1);
}
void *stl_malloc(size_t nbytes){
if(nbytes > 128){
return malloc(nbytes);
}
obj **my_free_list;
obj *result;
my_free_list = free_list + FREELIST_INDEX(nbytes);
result = *my_free_list;
if(result == NULL){
void *r = refill(ROUND_UP(nbytes));
return r;
}
//取出空闲块
*my_free_list = result->free_list_link;
return result;
}
void stl_free(void *p, size_t nbytes){
obj *q = (obj *)p;
obj **my_free_list;
if(nbytes > (size_t)__MAX_BYTES){
free(p);
return;
}
my_free_list = free_list + FREELIST_INDEX(nbytes);
q->free_list_link = *my_free_list;
*my_free_list = q;
}
void *refill(size_t n){
//默认从内存池取得20个块,多个块构成一个chunk
size_t nobjs = 20; //值-结果参数
char *chunk = chunk_alloc(n, &nobjs);
if(!chunk){
return NULL;
}
obj **my_free_list;
obj *result, *cur_obj, *next_obj;
int i;
//内存池空间告急仅返回一个块,则直接返回给用户
if(nobjs == 1){
return chunk;
}
//否则准备向free_list中纳入新的节点
my_free_list = free_list + FREELIST_INDEX(n);
//以下在chunk的连续空间上建立free_list
result = (obj *)chunk; //此块返回给用户
*my_free_list = next_obj = (obj *)(chunk + n);
for(i = 1; ; i++){
cur_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if(nobjs - 1 == i){
cur_obj->free_list_link = NULL;
break;
}else{
cur_obj->free_list_link = next_obj;
}
}
return result;
}
//从内存池取连续的块空间
char *chunk_alloc(size_t bytes, size_t *nobjs){
char *result;
size_t total_bytes = bytes * (*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 >= bytes){
//不够分配全部的,但是还可以分配一个或多个块
*nobjs = bytes_left/bytes;
total_bytes = *nobjs * bytes;
result = start_free;
start_free += total_bytes;
return result;
}else{
//内存池黔驴技穷了,连一个块的空间都没有了
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heapsize >> 4);
if(bytes_left > 0){
//内存池中还有一些零头,先配给适当的free-list
obj **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(start_free == NULL){
//看看更大块的free_list有无可用块
int i;
obj **my_free_list, *p;
for(i = bytes; i <= __MAX_BYTES; i += __ALIGN){
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if(p){
*my_free_list = p->free_list_link;
start_free = (char *)p;
end_free = start_free + i;
//递归调用自己,按新的状态重新分配,并修正nobjs;
return chunk_alloc(bytes, nobjs);
}
}
//实在没有空间了
end_free = 0;
return NULL;
}
heapsize += bytes_to_get;
end_free = start_free + bytes_to_get;
return chunk_alloc(bytes, nobjs);
}
}