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