网上对sbrk到底是system call 还是 library function说法不一
这里通过调用sbrk实现了一个简略的malloc函数,用双向链表管理内存块,内存块的分配用了首次适应算法。
据说linux源码里又插了一个红黑树数据结构将首次适应算法改进为最佳适应,好像很厉害的样子。
#include<unistd.h> #include<stdio.h> #include<time.h> #include<string.h> /************************************************************ * 目的:模拟标准库函数malloc和free,实现进程堆上的内存管理。 * 实现细节:1.使用显示双向链表,按地址顺序维护内存块。 * 2.使用首次适配算法进行空闲块的选择。 ***********************************************************/ #define has_used 1 #define has_not_used 0 #define MINSIZE 32 #define SIZE(p) (p->size) #define USED(p) (p->is_used) #define PRED(p) (p->pred) #define SUCC(p) (p->succ) void malloc_init(); void* my_malloc(long numbytes); void my_free(void *p); /*内存块数据结构*/ struct mem_block{ int is_used; long size; struct mem_block* pred; struct mem_block* succ; }; /********************************** * 全局变量定义: * 1.内存块头指针 * 2.内存块尾指针 * 3.分配器初始化标记 *********************************/ struct mem_block* head; struct mem_block* tail; int has_initialized = 0; /*初始化分配器*/ void malloc_init(){ head = sbrk(sizeof(struct mem_block)); tail = sbrk(sizeof(struct mem_block)); USED(head) = USED(tail) = has_used; PRED(head) = NULL; PRED(tail) = head; SUCC(head) = tail; SUCC(tail) = NULL; has_initialized = 1; } void* my_malloc(long numbytes){ struct mem_block *cur_block; struct mem_block *pred_block; void *mem_location = NULL; long block_size = numbytes + sizeof(struct mem_block); struct mem_block *alloc_block = NULL; if(numbytes <= 0) return NULL; if(!has_initialized){ malloc_init(); } cur_block = head; while(cur_block){ if(!USED(cur_block)){ if(SIZE(cur_block) >= numbytes){ /*将cur_block标记为已分配*/ USED(cur_block) = has_used; mem_location = (void*) cur_block + sizeof(struct mem_block); if(SIZE(cur_block) - numbytes > sizeof(struct mem_block)){ /*判断是否需要分割当前块*/ pred_block = SUCC(cur_block); alloc_block = (void*) cur_block + block_size; USED(alloc_block) = has_not_used; SIZE(alloc_block) = SIZE(cur_block) - numbytes - sizeof(struct mem_block); PRED(alloc_block) = cur_block; SUCC(alloc_block) = pred_block; SUCC(cur_block) = alloc_block; SIZE(cur_block) = numbytes; PRED(pred_block) = alloc_block; } break; } } cur_block=SUCC(cur_block); } /*没有找到合适的块,申请新的空间*/ /*这一步很关键,必须注意将tail块放置到最后才能保证链表中块的地址顺序*/ if(!mem_location){ pred_block = PRED(tail); sbrk(-1*sizeof(struct mem_block)); if( (long) (alloc_block = sbrk(block_size)) == -1){ printf("申请内存失败!\n"); return NULL; } tail = sbrk(sizeof(struct mem_block)); SIZE(alloc_block) = numbytes; USED(alloc_block) = has_used; SUCC(alloc_block) = tail; PRED(alloc_block) = pred_block; SUCC(pred_block) = alloc_block; PRED(tail) = alloc_block; SUCC(tail) = NULL; USED(tail) = has_used; SIZE(tail) = 0; mem_location = (void*) alloc_block + sizeof(struct mem_block); } return mem_location; } void my_free(void *p){ if(!p) return; struct mem_block* cur_block = p - sizeof(struct mem_block); /* 判断是否合并,四种情况,1.不合并。2.前合并。3.后合并。4.前后同时合并 */ /* 边界上的问题已经通过初始化解决了*/ struct mem_block* pred_block = PRED(cur_block); struct mem_block* succ_block = SUCC(cur_block); if(USED(pred_block)&&USED(succ_block)){ USED(cur_block) = has_not_used; } else if(!USED(pred_block)&&USED(succ_block)){ SIZE(pred_block) = SIZE(pred_block) + SIZE(cur_block) + sizeof(struct mem_block); SUCC(pred_block) = SUCC(cur_block); PRED(succ_block) = pred_block; } else if(USED(pred_block)&&!USED(succ_block)){ USED(cur_block) = has_not_used; SIZE(cur_block) = SIZE(cur_block) + SIZE(succ_block) + sizeof(struct mem_block); SUCC(cur_block) = SUCC(succ_block); if(SUCC(succ_block)) PRED(SUCC(succ_block)) = cur_block; } else if(!USED(pred_block)&&!USED(succ_block)){ SIZE(pred_block) = SIZE(pred_block) + SIZE(cur_block) + SIZE(succ_block) + 2 * sizeof(struct mem_block); SUCC(pred_block) = SUCC(succ_block); if(SUCC(succ_block)) PRED(SUCC(succ_block)) = pred_block; } } void memory_state(){ struct mem_block* cur_block = head; while(cur_block){ printf("size: %ld, used: %d,address: %p\n",SIZE(cur_block),USED(cur_block),cur_block); cur_block = SUCC(cur_block); } printf("\n"); } int main(){ int i,j,k; void* test[100]; memset(test,NULL,sizeof(test)); srand(time(NULL)); for(i=0;i<=3000000;i++){ j=rand()%100; if(test[j]){ //printf("释放\n"); my_free(test[j]); test[j] = NULL; } else{ k = rand()%1000; //printf("申请%d内存空间\n",k); test[j] = my_malloc(k); } } memory_state(); return 0; }
当然上面的实现再效率上来说是比较坑爹的= =!
稍微改进一下使用循环适配算法
#include<unistd.h> #include<stdio.h> #include<time.h> #include<string.h> /************************************************************ * 目的:模拟标准库函数malloc和free,实现进程堆上的内存管理。 * 实现细节:1.使用显示双向链表,按地址顺序维护内存块。 * 2.使用循环首次适应算法进行空闲块的选择。 ***********************************************************/ #define has_used 1 #define has_not_used 0 #define MINSIZE 32 #define SIZE(p) (p->size) #define USED(p) (p->is_used) #define PRED(p) (p->pred) #define SUCC(p) (p->succ) void malloc_init(); void* my_malloc(long numbytes); void my_free(void *p); /*内存块数据结构*/ struct mem_block{ int is_used; long size; struct mem_block* pred; struct mem_block* succ; }; /********************************** * 全局变量定义: * 1.内存块头指针 * 2.内存块尾指针 * 3.分配器初始化标记 * 4.遍历内存块的标记 *********************************/ struct mem_block* head; struct mem_block* tail; struct mem_block* flag; int has_initialized = 0; /*初始化分配器*/ void malloc_init(){ head = sbrk(sizeof(struct mem_block)); tail = sbrk(sizeof(struct mem_block)); USED(head) = USED(tail) = has_used; PRED(head) = tail; PRED(tail) = head; SUCC(head) = tail; SUCC(tail) = head; flag = head; has_initialized = 1; } void* my_malloc(long numbytes){ struct mem_block *cur_block; struct mem_block *pred_block; void *mem_location = NULL; long block_size = numbytes + sizeof(struct mem_block); struct mem_block *alloc_block = NULL; if(numbytes <= 0) return NULL; if(!has_initialized){ malloc_init(); } cur_block = flag; while(cur_block){ if(!USED(cur_block)){ if(SIZE(cur_block) >= numbytes){ /*将cur_block标记为已分配*/ USED(cur_block) = has_used; mem_location = (void*) cur_block + sizeof(struct mem_block); if(SIZE(cur_block) - numbytes > sizeof(struct mem_block)){ /*判断是否需要分割当前块*/ pred_block = SUCC(cur_block); alloc_block = (void*) cur_block + block_size; USED(alloc_block) = has_not_used; SIZE(alloc_block) = SIZE(cur_block) - numbytes - sizeof(struct mem_block); PRED(alloc_block) = cur_block; SUCC(alloc_block) = pred_block; SUCC(cur_block) = alloc_block; SIZE(cur_block) = numbytes; PRED(pred_block) = alloc_block; } break; } } cur_block=SUCC(cur_block); if(cur_block == flag) break; } flag = cur_block; /*没有找到合适的块,申请新的空间*/ /*这一步很关键,必须注意将tail块放置到最后才能保证链表中块的地址顺序*/ if(!mem_location){ pred_block = PRED(tail); sbrk(-1*sizeof(struct mem_block)); if( (long) (alloc_block = sbrk(block_size)) == -1){ printf("申请内存失败!\n"); return NULL; } tail = sbrk(sizeof(struct mem_block)); SIZE(alloc_block) = numbytes; USED(alloc_block) = has_used; SUCC(alloc_block) = tail; PRED(alloc_block) = pred_block; SUCC(pred_block) = alloc_block; PRED(tail) = alloc_block; SUCC(tail) = head; USED(tail) = has_used; SIZE(tail) = 0; PRED(head) = tail; mem_location = (void*) alloc_block + sizeof(struct mem_block); } return mem_location; } void my_free(void *p){ if(!p) return; struct mem_block* cur_block = p - sizeof(struct mem_block); /* 判断是否合并,四种情况,1.不合并。2.前合并。3.后合并。4.前后同时合并 */ /* 边界上的问题已经通过初始化解决了*/ struct mem_block* pred_block = PRED(cur_block); struct mem_block* succ_block = SUCC(cur_block); if(USED(pred_block)&&USED(succ_block)){ USED(cur_block) = has_not_used; } else if(!USED(pred_block)&&USED(succ_block)){ SIZE(pred_block) = SIZE(pred_block) + SIZE(cur_block) + sizeof(struct mem_block); SUCC(pred_block) = SUCC(cur_block); PRED(succ_block) = pred_block; flag = pred_block; } else if(USED(pred_block)&&!USED(succ_block)){ USED(cur_block) = has_not_used; SIZE(cur_block) = SIZE(cur_block) + SIZE(succ_block) + sizeof(struct mem_block); SUCC(cur_block) = SUCC(succ_block); PRED(SUCC(succ_block)) = cur_block; flag = cur_block; } else if(!USED(pred_block)&&!USED(succ_block)){ SIZE(pred_block) = SIZE(pred_block) + SIZE(cur_block) + SIZE(succ_block) + 2 * sizeof(struct mem_block); SUCC(pred_block) = SUCC(succ_block); PRED(SUCC(succ_block)) = pred_block; flag = pred_block; } } void memory_state(){ struct mem_block* cur_block = head; while(cur_block){ printf("size: %ld, used: %d,address: %p\n",SIZE(cur_block),USED(cur_block),cur_block); cur_block = SUCC(cur_block); if(cur_block == head) break; } printf("\n"); } int main(){ int i,j,k; void* test[100000]; memset(test,NULL,sizeof(test)); srand(time(NULL)); for(i=0;i<=50000000;i++){ j=rand()%100; if(test[j]){ // printf("释放\n"); my_free(test[j]); test[j] = NULL; } else{ k = rand()%1000; // printf("申请%d内存空间\n",k); test[j] = my_malloc(k); } } memory_state(); return 0; }