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

//作者  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

發佈了33 篇原創文章 · 獲贊 10 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章