网上对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;
}