C程序中的存儲分配

 

C程序中的存儲分配

分類: GNU/LINUX C/C++ 數據存儲 數據結構與算法 731人閱讀 評論(4) 收藏 舉報
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 NALLOC 1024 /* 最小申請單元數 */

typedef 
long Align;  /**//* 按照long類型的邊界對齊 */

union header         
/**//* 塊的頭部 */
...{
  
struct ...{
    union header 
*ptr;    /**//* 空閒塊的鏈表的下一塊 */
    unsigned size;    
/**//* 本塊的大小 */
  }
s;
  Align x;        
/**//* 強制塊的對齊 */
}
;

typedef union header Header;

static Header base;        /**//* 從空鏈表開始 */
static Header *freep = NULL;    /**//* 空閒鏈表的初始指針 */

/**//* free 函數:將塊ap放入空閒塊鏈表中 */
void free(void *ap)
...{
  Header 
*bp, *p;
  bp 
= (Header*)ap -1;

  
for ( p = freep ; !(bp>&&bp < p->s.ptr); p = p->s.ptr)
    
if ( p >= p->s.ptr && (bp >||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( unsigned nu)
...{
  
char *cp, *sbrk(int );
  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;
  free ((
void*)(up+1));
  
return freep;
}


/**//* mumalloc: 存儲分配函數 */
void *mymalloc (unsigned nbytes)
...{
  Header 
*p, *prevp;
  Header 
*morecore(unsigned);
  unsigned nunits;

  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)
        
return NULL;    /**//* 沒有剩餘的存儲空間 */
  }

}


/**//* 主函數:測試mymalloc函數 */
int main(void)
...{
  
char * p ;

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

更詳細的程序說明請直接參考"The C Programming Language"一書162 ~ 166頁。
上一篇:C存儲類型和類型限定符 下一篇:散列表設計
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章