打造自己的堆存储分配策略

//作者  RobinKin  from  DevonIT .inc

#ifndef MEMORY_C
#define MEMORY_C


//#define TEST_MEMORY
#define IOS
#define DEBUG
//#define TEST_LITTLE
/*本系统开了一个特定大小的栈区,在这个区域上模拟堆存储管理
 * 提供了两个关键的函数 malloc(int) 和free(void *)
 *
 * *这个版本的系统,使用了一个256k大小的栈
 * 分成256大份,每份1k大小,
 * 如果用户申请大于1k大小的空间,
 * 则直接用伙伴算法通过大的Buddy_table(大表)找到一块合适大小的空闲块;
 *
 * 如果用户申请小于1k大小的空间,
 * 则在一个1k的空闲块上,建立一个小的Buddy_table(小表)
 * 一个小表管理32块,大小是32字节的小块。
 * 一个小表分配完之后,建立新的一个小表,直到大表的空间也满为止
 *
 * 空间分配完的话,再申请空间时候,报memory full错
 * */

#define NULL 0
#ifdef IOS
#include<iostream>
using namespace std;
#endif

#define malloc my_malloc
#define free my_free

#define UCHAR unsigned char
#define USHORT unsigned short

void * malloc(int size); //分配一段空间
void free(void *);  //释放一个指针#define NULL 0


void free_little(void * addr);
void free_big(void * addr);

#define FALSE 0
#define TRUE 1

#define BIG_BLOCK_SIZE  1024 //大块每个1k
#define BIG_BLOCK_MAX 256//有多少个1k的大块
#define STACK_MAX  BIG_BLOCK_SIZE*BIG_BLOCK_MAX //
#define BLOCKID_MAX 2*BIG_BLOCK_MAX  //二叉树结点


//第一个结点分割1024*128+1024*128,第2,3个进一步分割
//1+2+4...+2^8=2^^9-1 ,


#define LITTLE_BLOCK_SIZE 32 //32个字节一个小块
#define LITTLE_BLOCK_MAX  BIG_BLOCK_SIZE/LITTLE_BLOCK_SIZE  //1024/32
#define LITTLE_BLOCKID_MAX 2*LITTLE_BLOCK_MAX
char SYS_STACK[STACK_MAX];//存储池

 

struct Buddy_address_table{
void * address[BIG_BLOCK_MAX];//起始地址
USHORT occu_id[BIG_BLOCK_MAX];//hash位置是否占用,0表示未占用,非0的话指向占用的id

bool semi[BLOCKID_MAX];//是否被部分占用,用这个数组表示一棵二叉
bool occupied[BLOCKID_MAX];//是否被完全占用,用这个数组表示一棵二叉树
};

Buddy_address_table bd={NULL};

struct Little_Buddy{
void * address[LITTLE_BLOCK_MAX];//起始地址
UCHAR occu_id[LITTLE_BLOCK_MAX];//hash位置是否占用,0表示未占用,非0的话指向占用的id

bool semi[LITTLE_BLOCKID_MAX];//是否被部分占用,用这个数组表示一棵二叉树
bool occupied[LITTLE_BLOCKID_MAX];//是否被完全占用,用这个数组表示一棵二叉树

int idx;//小表本身在大表中的idx(释放小表时要用到)
bool full;
};

void *find_little_space(Little_Buddy * lb,int i,int size,void * addr);
void * find_space(int i, int size,void * addr);
void error(int x){
#ifdef DEBUG
#endif
};


int big_size(int idx){

 int s=STACK_MAX;
 int i;
 while(idx!=1){
  s=s/2;
  if(idx%2==0){
   idx=idx/2;
  }
  else{
   idx=(idx-1)/2;
  }
 }
 return s;
}

int little_size(int idx){

 int s=BIG_BLOCK_SIZE;
 int i;
 while(idx!=1){
  s=s/2;
  if(idx%2==0){
   idx=idx/2;
  }
  else{
   idx=(idx-1)/2;
  }
 }
 return s;
}

 

//建立一个释放信息栈,每次受到释放信号的时候,不马上释放,而是先进栈
//栈满或者空间已经满时,一起释放,提高效率
//
Little_Buddy * lb_list[BIG_BLOCK_MAX]={NULL};

//最多BIG_BLOCK_MAX个小表--一个大BUDDY块可以是一个小BUDY表

 

int get_idx_little(Little_Buddy * lb, void *addr){
 int i=(int)addr;
 int k=i%LITTLE_BLOCK_MAX;
 while(lb->occu_id[k]){
  k++;
  if(k==LITTLE_BLOCK_MAX){
   k=0;
  }
 }
 return k;//找到addre的插入位置
}
int get_idx(void *addr){
 int i=(int)addr;
 int k=i%BIG_BLOCK_MAX;
 while(bd.occu_id[k]){
  k++;
  if(k==BIG_BLOCK_MAX){
   k=0;
  }
 }
 return k;//找到addre的插入位置
}


void * malloc(int size){
void * addr;
int idx;//查到的空闲块id

#ifdef DEBUG 
cout<<"target space:"<<size<<endl;
#endif


if(size<=BIG_BLOCK_SIZE){//比较小的块,用小表分配
 int i=0;
 
 while(lb_list[i]!=NULL && lb_list[i]->full!=1){

#ifdef DEBUG
 cout<<"search little"<<endl;
#endif
 
  //已经建立的小表中,未满的表
  if(addr=find_little_space(lb_list[i],1,size,lb_list[i])){
   return addr;
  }
  i++;
 }
 //现有小表中找不到足够空间,建立新的小表

 if(addr=find_space(1,BIG_BLOCK_SIZE,SYS_STACK)){//在大表中找到空间
  
  lb_list[i]=(Little_Buddy*)addr;// 小表本身所占的空间

  //little table initialize
  int j;
  for(j=0;j<LITTLE_BLOCKID_MAX;j++){
   lb_list[i]->occupied[j]=FALSE;
   lb_list[i]->semi[j]=FALSE;
  }

  for(j=0;j<LITTLE_BLOCK_MAX;j++){
   lb_list[i]->occu_id[j]=0;

  }
   
  lb_list[i]->idx=idx;

   //去掉小表本身的空间
  find_little_space(lb_list[i],1,sizeof(Little_Buddy),addr);
   
  //通过小表所描述的空闲块空间查找合适小空闲块
  if(addr=find_little_space(lb_list[i],1,size,addr)){
   return addr;
  }
  else{
   return NULL;
  }
  
 }
}
return  find_space(1,size,SYS_STACK);//从根结点开始找可用空间

}


//
//
void *find_little_space(Little_Buddy * lb,int i,int size,void * addr){

if(LITTLE_BLOCK_SIZE>size){size=LITTLE_BLOCK_SIZE;}
int sz=little_size(i);


 
if(LITTLE_BLOCKID_MAX<i){return NULL;}
if(lb->occupied[i]){return NULL;};


//半可用空间
if(lb->semi[i]){

#ifdef DETAIL
 cout<<"semi"<<i<<" "<<sz<<" "<<size<<endl;
#endif
 
 if(sz<=2*size){
  return NULL;
 }
 else{
  if(!lb->occupied[2*i]){
   void * adr;
   if(adr=find_little_space(lb,2*i,size,addr)){
    return adr;
   }
  }
  else{
   char * ad=(char*)addr;
   return find_little_space(lb,2*i+1,size,ad+sz/2);
  }
 }
}

//是完全可用空间
if(sz>=size){//存在可用空间

#ifdef DETAIL
 cout<<"space:"<<i<<" "<<sz<<" "<<size<<endl;
#endif
 
 if(sz>=2*size ){//还太大,继续分小的
  lb->semi[i]==1;//本身半占
   
  void * adr;
  if (adr= find_little_space(lb,2*i,size,addr)){
   return adr;
  }
  else{
   char * ad=(char*)addr;
   return find_little_space(lb,2*i+1,size,ad+sz/2);
  };
 }

 //找到合适的可用空间

  
 int k=get_idx_little(lb,addr);
  
 lb->address[k]=addr;
 lb->occu_id[k]=i;//记下对应地址的id 小表
 lb->occupied[i]=TRUE;

#ifdef DEBUG
 cout<<"space:"<<i<<" "<<sz<<" "<<size<<endl;
#endif
  
 return addr;//返回存储空间首地址
 
 
}
else{
 //所申请的块的大小已经超过这个小表的最大限度
 lb->full=1;
 return NULL;
  

}
}
//
//


void * find_space(int i, int size,void * addr){// 从 index开始找大小是size 的块

if(BIG_BLOCK_SIZE>size){size=BIG_BLOCK_SIZE;}
int sz=big_size(i);

#ifdef DETAIL
 cout<<i<<" "<<sz<<" "<<size<<endl;
#endif
if(BLOCKID_MAX<i){return NULL;}
if(bd.occupied[i]){
#ifdef DETAIL
 cout<<"occupied:"<<i<<endl;
#endif
 return NULL;
}


//半可用空间
if(bd.semi[i]){
 if(sz<=2*size){
  return NULL;
 }
 else{
  if(!bd.occupied[2*i]){
   void * adr;
   if(adr=find_space(2*i,size,addr)){
    return adr;
   }
  }
  else{
   char * ad=(char*)addr;
   return find_space(2*i+1,size,ad+sz/2);
  }
 }
}

//是完全可用空间
if(sz>=size){//存在可用空间
 if(sz>=2*size ){//还太大,继续分小的
  bd.semi[i]==1;//本身半占
   
  void * adr;
  if (adr= find_space(2*i,size,addr)){
   return adr;
  }
  else{
   char * ad=(char*)addr;
   return find_space(2*i+1,size,ad+sz/2);
  };
 }

 //找到合适的可用空间

  
 int k=get_idx(addr);
  
 bd.address[k]=addr;
 bd.occu_id[k]=i;//记下对应地址的id 小表
 bd.occupied[i]=TRUE;

#ifdef DEBUG
 cout<<i<<" "<<sz<<" "<<size<<endl;
#endif
   
 return addr;//返回存储空间首地址
 
 
}
else{
 //所申请的块的大小已经超过这个表的最大限度
#ifdef DEBUG
 cout<<"memory full"<<endl;
#endif
 return NULL;
  

}

 

#ifdef DETAIL
 cout<<"begin to assign "<<i<<endl;
#endif
 
if(!bd.occupied[i] && sz>size){//存在可用空间
 
 if(sz>2*size){//还太大,继续分小的
  bd.occupied[i]==TRUE;//本身不空
 
#ifdef DETAIL
  cout<<"virtual assign"<<i<<" "<<sz<<endl<<endl;
#endif
   
  void * adr;
  if (adr= find_space(2*i,size,addr)){
  bd.occupied[2*i]=1;//左结点不空
  return adr;
  }
  else{
  char * ad=(char *)addr;
  bd.occupied[2*i+1]=1;//左结点不空
  return find_space(2*i+1,size,ad+sz/2);
  };
 }

 else{ //找到合适的可用空间

 int k=get_idx(addr);
 
 bd.address[k]=addr;
 bd.occu_id[k]=i;//记下对应地址的id 小表
 
#ifdef DETAIL

 cout<<"occu_id: "<<k<<" "<<(int)addr<<endl;
#endif


#ifdef DEBUG
 cout<<"best suit:"<<i<<" "<<sz<<endl;
#endif
 
 return bd.address[k];//返回存储空间首地址和空间大小
 }
 
}
else{
#ifdef DETAIL
 cout<<"begin search sub_node"<<endl;
#endif
 if(bd.occupied[i]){//本块占用
  void * adr;
  if(adr=find_space(2*i,size,addr)){//找左结点
  return adr;
  }    else{
   char * ad=(char*)addr;
  return find_space(2*i+1,size,ad+sz/2);
  }
 
 }


         else{//所申请的块的大小已经超过最大限度
  
  error(98);
#ifdef DEBUG
  if(1==i){
  cout<<"memory full"<<endl;
  }
#endif
  return NULL;
  
 }

}
}
//
//
void free_big_id(int k){//释放上层虚结点

if(0==k){
 
#ifdef DEBUG1 
cout<<"root "<<endl;
#endif
 return;
}

if(1==k){
 
#ifdef DEBUG 
cout<<"root freed"<<endl;
#endif

bd.occupied[1]=FALSE;//清空索引所指向的空间
bd.semi[1]=FALSE;//清空索引所指向的空间
return;
}

 

if(0==k%2){//左结点
 
 #ifdef DETAIL
 cout<<k<<" left virutal freed"<<endl;
 #endif
 
 if(!bd.occupied[k+1]|| !bd.semi[k+1]){//右边也空

 #ifdef DETAIL
 cout<<k+1<<" right blank too"<<endl;
 #endif
 
 free_big_id(k/2); 
 bd.occupied[k]=FALSE;//清空索引所指向的空间
 bd.semi[k]=FALSE;//清空索引所指向的空间
 }
}
else{//是右结点

 #ifdef DETAIL
 cout<<k<<" right virutal freed"<<endl;
 #endif

 if(!bd.occupied[k-1] || !bd.semi[k-1]){//左边也空

 #ifdef DEBUG
 cout<<k-1<<"left blank too"<<endl;
 #endif
 

 free_big_id((k-1)/2); 
 bd.occupied[k]=FALSE;//清空索引所指向的空间
 bd.semi[k]=FALSE;//清空索引所指向的空间
 
 }
 

}
}//end
//
//
int  memory_size_little(void * addr){

int target=(int)addr;
int d;
for(int d=0;d<BIG_BLOCK_MAX;d++){
 int head=(int)lb_list[d];
 int tail=(int)((char*)lb_list[d]+BIG_BLOCK_SIZE);
 if(target>=head &&target<tail){
  int k=target%LITTLE_BLOCK_MAX;

  Little_Buddy * p=lb_list[d];
  while(p->address[k]!=addr ||!p->occu_id[k]){
   k++;
   if(k==BIG_BLOCK_MAX){
    k=0;
   }
  }
 
  return little_size(p->occu_id[k]);
 }
}

 return -1;
  
}

int memory_size_big(void * addr){

int target=(int)addr;

int head=target%BIG_BLOCK_MAX;
int tail=head;

#ifdef DETAIL
cout<<head<<" "<<(int)addr<<endl;
#endif

if(bd.address[head]==addr && bd.occu_id[head]!=0 ){
 ;
}

else{
 head++;
 while(
  tail!=head &&
  (bd.occu_id[head]==0 || bd.address[head]!=addr  )
 ){
 #ifdef DEBUG
 
 //  cout<<(int)bd.address[head]<<" ";
 #endif

 head++;
  if(head==BIG_BLOCK_MAX){
   head=0;
  }
 }
}

 

int k=head;
if(head==tail){
 return memory_size_little(addr);
}

return big_size(bd.occu_id[k]);


}

 


//
void free_big(void * addr){

int target=(int)addr;

int head=target%BIG_BLOCK_MAX;
int tail=head;

#ifdef DETAIL
cout<<head<<" "<<(int)addr<<endl;
#endif

if(bd.address[head]==addr && bd.occu_id[head]!=0 ){
 ;
}

else{
 head++;
 while(
  tail!=head &&
  (bd.occu_id[head]==0 || bd.address[head]!=addr  )
 ){
 #ifdef DEBUG
 
 //  cout<<(int)bd.address[head]<<" ";
 #endif

 head++;
  if(head==BIG_BLOCK_MAX){
   head=0;
  }
 }
}

 

int k=head;
if(head==tail){
 free_little(addr);
}


if(1==bd.occu_id[k]){//不是根结点
 
#ifdef DEBUG
 cout<<"big root freed"<<endl;
#endif

 bd.occupied[1]=FALSE;//清空索引所指向的空间
 bd.semi[1]=FALSE;//清空索引所指向的空间
 bd.occu_id[k]=0;//空出一个索引位置


 return;
}


if(bd.occu_id[k]%2==0 ){//左结点
#ifdef DEBUG
 cout<<bd.occu_id[k]<<"left real  freed"<<endl;
#endif
 
 
 if(!bd.occupied[bd.occu_id[k]+1]){//右边也空
  free_big_id(bd.occu_id[k]/2);
   
 }
 
 
 

}
else{//是右结点
#ifdef DEBUG
 cout<<bd.occu_id[k]<<"right real freed"<<endl;
#endif

 if(!bd.occupied[bd.occu_id[k]-1]){//左边也空
  free_big_id((bd.occu_id[k]-1)/2);
 }
 
}

 bd.occupied[bd.occu_id[k]]=FALSE;//清空索引所指向的空间
 bd.semi[bd.occu_id[k]]=FALSE;//清空索引所指向的空间
 bd.occu_id[k]=0;//空出一个索引位置

 


}
//
void free_little_id(Little_Buddy * p,int k){
 
if(0==k){
 
#ifdef DEBUG
cout<<"root "<<endl;
#endif
 return;
}

if(1==k){
 
#ifdef DEBUG 
cout<<"little root freed "<<endl;
#endif

p->occupied[1]=FALSE;//清空索引所指向的空间
p->semi[1]=FALSE;//清空索引所指向的空间
return;
}

if(0==k%2){//左结点
 
 #ifdef DEBUG1
 cout<<k<<" left virutal freed"<<endl;
 #endif
 
 if(!p->occupied[k+1] || !p->semi[k+1]){//右边也空

 #ifdef DEBUG1
 cout<<k+1<<" right blank too"<<endl;
 #endif
 
 free_little_id(p,k/2); 
 p->occupied[k]=FALSE;//清空索引所指向的空间
 p->semi[k]=FALSE;//清空索引所指向的空间
 }
}
else{//是右结点

 #ifdef DEBUG1
 cout<<k<<" right virutal freed"<<endl;
 #endif

 if(!p->occupied[k-1]||!p->semi[k-1]){//左边也空

 #ifdef DEBUG1
 cout<<k-1<<"left blank too"<<endl;
 #endif
 

 free_little_id(p,(k-1)/2); 
 p->occupied[k]=FALSE;//清空索引所指向的空间
 
 }
 

}
}//end free_little_id
//
//
void free_little(void * addr){

int target=(int)addr;
int d;
for(int d=0;d<BIG_BLOCK_MAX;d++){
 int head=(int)lb_list[d];
 int tail=(int)((char*)lb_list[d]+BIG_BLOCK_SIZE);
 if(target>=head &&target<tail){
  int k=target%LITTLE_BLOCK_MAX;

  Little_Buddy * p=lb_list[d];
  while(p->address[k]!=addr ||!p->occu_id[k]){
   k++;
   if(k==BIG_BLOCK_MAX){
    k=0;
   }
  }
 
  int id=p->occu_id[k];

  p->occupied[id]=FALSE;
  p->semi[id]=FALSE;

#ifdef DEBUG1
  cout<<"idx"<<k<<endl<<endl;
#endif
 
  if(id==1){//是小表根结点
   free(p);//释放掉小表根

#ifdef DEBUG
   cout<<"free little table"<<endl<<endl;
#endif
 
  }

 

  

  if(id%2==0){//左结点

   if(!p->occupied[id+1] &&!p->semi[id+1]){//右边也空
#ifdef DEBUG
    cout<<" right also blank:"<<id<<endl<<endl;
#endif
    free_little_id(p,id/2);//释放上层结点  
    return;
   }
  }


  else{//右结点
   if(!p->occupied[p->occu_id[k]-1]){//左边也空
#ifdef DEBUG
    cout<<"left also blank:"<<p->occu_id[k]<<endl<<endl;
#endif
    free_little_id(p,(id-1)/2);//释放上层结点  
    return;
   }

  }
 }
}
}
//

 

 

 

 


//
void free(void * addr){
 
int target=(int)addr;
int base=(int)SYS_STACK;

if(target<base ||target>base+STACK_MAX){return;}
if((target-base)% BIG_BLOCK_SIZE==0){//是大表上的结点,BIG_BLOCK_SIZE为单位分配
#ifdef DEBUG
 cout<<"free_big"<<endl;
#endif
 free_big(addr);
}

else{//小表
#ifdef DEBUG
 cout<<"free_little"<<endl;
#endif
 
 free_little(addr);


}

int memory_size(void * addr){ // chech that how many space has assign to it
int target=(int)addr;
int base=(int)SYS_STACK;

if(target<base ||target>base+STACK_MAX){return -1;}
if((target-base)% BIG_BLOCK_SIZE==0){//是大表上的结点,BIG_BLOCK_SIZE为单位分配
#ifdef DEBUG
 cout<<"free_big"<<endl;
#endif
 return memory_size_big(addr);
}

else{//小表
#ifdef DEBUG
 cout<<"size_little"<<endl;
#endif
 
 return memory_size_little(addr);
}
}

/*
 *99 未知错误
 98 空间不足
 96 释放一个buddy系统中没有的地址(指针)
 *
 * */
#ifdef TEST_MEMORY
int main(){
 
double * d[10];

#ifdef TEST_BIG
int * a=(int*)malloc(1000*sizeof(int));
a[999]=1;
free(a);

double * d[10];
d[0]=(double *)malloc(2000*sizeof(double));
d[1]=(double *)malloc(2000*sizeof(double));
d[2]=(double *)malloc(4000*sizeof(double));
d[3]=(double *)malloc(8000*sizeof(double));


int i;
for(i=0;i<4;i++){
 free(d[i]);
}

//d[0]=(double *)malloc(8000*sizeof(double));
d[1]=(double *)malloc(16000*sizeof(double));
//d[2]=(double *)malloc(4000*sizeof(double));
//d[3]=(double *)malloc(8000*sizeof(double));
d[1][15999]=1;
free(d[1]);

d[1]=(double *)malloc(32000*sizeof(double));

free(d[1]);

d[1]=(double *)malloc(42000*sizeof(double));
#endif

#ifdef TEST_LITTLE
d[0]=(double *)malloc(2);
d[1]=(double *)malloc(4);
d[2]=(double *)malloc(8);
d[3]=(double *)malloc(16);
d[4]=(double *)malloc(32);
d[5]=(double *)malloc(64);
int i;
for(i=0;i<6;i++){
 free(d[i]);
}
#endif
}

#endif //endif TEST_MEMORY

#endif//endif MEMORY_C

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值