C程序中的存储分配

C程序中的存储分配

(刘爱贵 - Aiguille.LIU)

  C程序设计中,经常需要使用malloc/free动态管理内存,在需要的时候向操作系统申请空间,适合的时候释放不再使用的空间。那么,C库中malloc/free是如何实现的呢?参考"The C Programming Language",我们设计了自己的存储分配程序。

  由于程序中某些地方可能不通过malloc调用申请空间,因此,malloc管理的空间不一下是连续的。这样,空闲存储空间以空闲链表的方式组织,每个块包含一个长度、一个指向下一块的指针以及一个指向自身的存储空间的指针。这些块按照存储地址的升序组织,最后一块指向第一块。
  
  当有申请请求时,malloc将扫描空闲块链表,直到找到一个足够大的块为止。这种算法称为“首次适应(first fit)”。与之相对的算法是“最佳适应(best fit)”,它寻找满足条件的最小块。如果该块恰好与请求的大小相符合,则将它从链表中移走并返回用户。如果该块太大,则将它分成两部分:大小合适的块返回给用户,剩下的部分留在空闲块链表中。如果找不到一个足够大的块,则向操作系统申请一个大块并加入到空闲块链表中。

  释放过程也是首先搜索空闲块链表,以找到可以插入被释放块的合适位置。如果与被释放块相邻的任一边是一个空闲块,则将这两个块合成一个更大的块,这样存储空间不会有太多的碎片。因为空闲块链表是以地址的递增顺序链接在一起的,所以很容易判断相相邻的块是否空闲。

  malloc函数返回的存储空闲要求满足将要保存的对象的对齐要求。虽然机器类型各异,但是,每个特定的机器都有一个最受限的类型:如果最受限的类型可以存储在某个特定的地址中,则其他所有的类型也可以存放在此地址中。在某些机器中,最受限的类型是double;而在另外一些机器中,最受限的类型是int或long类型。

  下面的my_malloc.c程序,简化了块的对齐,所有块的大小都是头部大小的整数倍,且头部已正确地对齐。空闲块开始处的控制信息称为“头部”。假定long类型为最受限的类型:
#include < stdio.h >
#include
< string .h >

#define NALLOC1024 /*最小申请单元数*/

typedef
long Align; /**/ /*按照long类型的边界对齐*/

unionheader
/**/ /*块的头部*/
... {
struct...{
unionheader
*ptr;/**//*空闲块的链表的下一块*/
unsignedsize;
/**//*本块的大小*/
}
s;
Alignx;
/**//*强制块的对齐*/
}
;

typedefunionheaderHeader;

static Header base ; /**/ /*从空链表开始*/
static Header * freep = NULL; /**/ /*空闲链表的初始指针*/

/**/ /*free函数:将块ap放入空闲块链表中*/
void free( void * ap)
... {
Header
*bp,*p;
bp
=(Header*)ap-1;

for(p=freep;!(bp>p&&bp<p->s.ptr);p=p->s.ptr)
if(p>=p->s.ptr&&(bp>p||bp<p->s.ptr))
break;/**//*被释放的块在链表的开头或未尾*/

if(bp+bp->s.size==p->s.ptr)...{/**//*与上一相邻块合并*/
bp
->s.size+=p->s.ptr->s.size;
bp
->s.ptr=p->s.ptr->s.ptr;
}
else
bp
->s.ptr=p->s.ptr;

if(p+p->s.size==bp)...{/**//*与下一相邻块合并*/
p
->s.size+=bp->s.size;
p
->s.ptr=bp->s.ptr;
}
else
p
->s.ptr=bp;
freep
=p;
}


/**/ /*morecore:向系统申请更多的存储空间*/
static Header * morecore(unsignednu)
... {
char*cp,*sbrk(int);
Header
*up;

if(nu<NALLOC)
nu
=NALLOC;
cp
=sbrk(nu*sizeof(Header));
if(cp==(char*)-1)/**//*没有空闲空间*/
returnNULL;
up
=(Header*)cp;
up
->s.size=nu;
free((
void*)(up+1));
returnfreep;
}


/**/ /*mumalloc:存储分配函数*/
void * mymalloc(unsignednbytes)
... {
Header
*p,*prevp;
Header
*morecore(unsigned);
unsignednunits;

nunits
=(nbytes+sizeof(Header)-1)/sizeof(Header)+1;
if((prevp=freep)==NULL)...{/**//*没有空闲链表*/
base.s.ptr=freep=prevp=&base;
base.s.size=0;
}


for(p=prevp->s.ptr;;prevp=0,p=p->s.ptr)...{
if(p->s.size>=nunits)...{/**//*足够大*/
if(p->s.size==nunits)/**//*正好*/
prevp
->s.ptr=p->s.ptr;
else...{/**//*分配未尾部分*/
p
->s.size-=nunits;
p
+=p->s.size;
p
->s.size=nunits;
}


freep
=prevp;
return(void*)(p+1);
}


if(p==freep)/**//*闭环的空闲链表*/
if((p=morecore(nunits))==NULL)
returnNULL;/**//*没有剩余的存储空间*/
}

}


/**/ /*主函数:测试mymalloc函数*/
int main( void )
... {
char*p;

p
=(char*)mymalloc(30);
strcpy(p,
"helloworld");
printf(
"%s ",p);
}

更详细的程序说明请直接参考"The C Programming Language"一书162 ~ 166页。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值