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