malloc函数模拟实现(其实说原创有点勉强)

来源:互联网 发布:韩国软件naver 编辑:程序博客网 时间:2024/05/16 00:54

malloc函数的原理很简单,首先利用系统调用(linux平台和windows平台都提供了从堆区动态分配内存的系统调用)从堆区申请一块内存,每当应用程序申请内存时,从这块内存区截取一块提供给程序。这样可以减少利用系统调用申请内存的次数,提高了效率。就好比批发商从厂商那里批发了很多商品,然后卖给消费者。从而方便了消费者。不用需要商品时都要从厂商那里购买。但是malloc的实现涉及到了很多细节。其中涉及到地址对齐,内存碎片,等等很多问题。要想实现一个malloc函数绝不是一件容易的事情。

在《c语言程序设计》(c语言之父写的那本)一书中,作者给出了一个malloc的模拟实现。一段很小的程序,可以说麻雀虽小五脏俱全。这个程序涉及到了malloc中要考虑的大部分问题,而且实现的非常简洁。我测试了一下和malloc具有一样的功能。代码不太好懂,我在不太容易理解的地方加了一些注释。以下是代码,在linux平台测试通过。如果想仔细了解,请看原书。

#define NALLOC 1024#define NULL 0typedef long Align;union header {struct {union header *ptr;//指向下一块空闲快unsigned size;//当前空闲块的大小} s;Align x;//x主要是保证分配的内存为Align的倍数。涉及到内存对齐};typedef union header Header;static Header base;static Header *freep=NULL;static Header *morecore(unsigned);void *mymalloc(unsigned nbytes){Header *p,*prevp;       unsigned nunites;nunites =(nbytes+sizeof(Header)-1)/sizeof(Header)+1;//分配的内存大小if((prevp =freep)==NULL){//no free list yet,the first call mallocbase.s.ptr =freep=prevp=&base;base.s.size=0;}for(p=prevp->s.ptr; ;prevp=p,p=p->s.ptr){if(p->s.size>=nunites){ //big enoughif(p->s.size==nunites)//exactlyprevp->s.ptr=p->s.ptr;else{//allocate tail end总是从每块空闲快的尾部截取p->s.size-=nunites;p+=p->s.size;p->s.size=nunites;}freep=prevp;return (void *)(p+1);}if(p==freep){if((p=morecore(nunites))==NULL)return NULL;}}}void myfree(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;}elsep->s.ptr=bp;freep=p;}static Header *morecore(unsigned nu){char *cp, *sbrk(int);//linux系统调用,扩展堆空间Header *up;if(nu<NALLOC)nu=NALLOC;cp=sbrk(nu*sizeof(Header));if(cp==(char*)-1)return NULL;up=(Header*)cp;up->s.size=nu;myfree((void *)(up+1));return freep;}

疑惑:
malloc申请得到的内存在未使用时,分配物理空间了吗?就是虚拟地址映射到物理地址了吗?还是访问这块内存发现缺页之后在分配物理空间呢。