malloc & free

來源:互聯網
上載者:User

 

CosOS核心中使用一個核心堆來管理記憶體,核心通過kmalloc和kfree從核心堆中申請和釋放記憶體。CosOS為使用者態編寫的庫函數中也實現了使用者態堆,應用程式通過malloc和free從堆中申請釋放記憶體。       核心堆和使用者態堆的演算法類似,都通過調用alloc和free_int來操作堆。下面以代碼和注釋的形式詳細介紹CosOS中 alloc和free_int這兩個函數的實現。在堆中,可以用的空閑記憶體塊成為hole,堆使用了一個鏈表來儲存堆中所有可用的hole。Alloc函數就是在這個鏈表中尋找到一個大小合適的hole然後根據請求分配的大小把hole切分成兩部分,一部分返回給調用者使用,剩下的重新加入到鏈表中。/*    alloc兩個參數,size代表請求分配記憶體的大小,page_align代表請求記憶體空間的首地址是否必須頁對齊,即地址是能被0x1000整除的。實現這個特性是因為核心中有些空間必須頁對齊,例如頁表、也目錄。*/void *alloc(u32int size, u8int page_align){         register struct hole *hp, *prev_ptr;         u32int old_base;         prev_ptr = NIL_HOLE;         hp = hole_head;//通過變數hole鏈表,尋找一個合適的holewhile(hp != NIL_HOLE)          {                   if(page_align)                   {//由於頁數限制,頁對齊實現部分代碼省略。                   }else if (hp->h_len >= size)                    {//找到了一個足夠大的hole,使用這個hole。//將其地址儲存在臨時變數old_base中,作為alloc的傳回值,                            old_base =hp->h_base;   //由於hole比請求的空間大,剩餘部分需放入堆中。只需重新調整hole的首地址和長度即可                            hp->h_base +=size;                             hp->h_len -=size;//記住使用使用過的記憶體當中,最高的地址,儲存在high_watermark當中                            if(hp->h_base > high_watermark)                                     high_watermark= hp->h_base;//經過上面代碼調整hole的大小之後,如果hole的大小為0,即hole的大小與請求大小相同,則將其從hole鏈表中移除。                            if (hp->h_len == 0)                                      del_slot(prev_ptr,hp);//返回分配記憶體塊得首地址。                            return (void*)(old_base);                   }                   prev_ptr = hp;                   hp = hp->h_next;         }//若運行到這裡,說明堆中沒有合適的記憶體塊,返回一個null 指標。         return0;}free_int用於將首地址為base,長度為clicks的記憶體塊釋放,重新加入到堆的hole列表中。void free_int(u32int base, u32int clicks){  struct hole*hp, *new_ptr, *prev_ptr;//如果要釋放的記憶體塊大小為0,則直接返回  if (clicks ==0)           return;  if ( (new_ptr= free_slots) == NIL_HOLE)        ASSERT(0);//將記憶體塊設定成一個holenew_ptr->h_base = base;  new_ptr->h_len = clicks;  free_slots = new_ptr->h_next;  hp = hole_head;//如果記憶體塊得地址是當前hole鏈表中最小的或者hole鏈表為空白,則把它插入到鏈表的第一個位置。  if (hp ==NIL_HOLE || base <= hp->h_base) {//插入到第一個位置         new_ptr->h_next = hp;         hole_head = new_ptr;//檢測是否能與相鄰的hole合并成一個更大的hole,這樣可以減少記憶體片段。merge(new_ptr);         return;  }//hole沒有被加入到首位置,則執行下面代碼  prev_ptr = NIL_HOLE;//hole鏈表中的hole是按照記憶體塊首地址由低到高排序的,插入新的hole時必須保證插入之後鏈表還是有序的。因此需要找到一個合適的位置插入。  while (hp !=NIL_HOLE && base > hp->h_base) {         prev_ptr = hp;         hp = hp->h_next;  }//找到了合適的位置,插入其中  new_ptr->h_next = prev_ptr->h_next;  prev_ptr->h_next = new_ptr;//檢測是否能與相鄰的hole合并成一個更大的hole,這樣可以減少記憶體片段。  merge(prev_ptr);   }Hole合并的實現較為簡單,只需檢測hole的base加上size是否與下一hole的base相同即可。這裡不詳細介紹alloc和free_int是最核心最原始的兩個函數。free_int使用時第二個參數需要確定釋放記憶體的大小,而使用者態的malloc、free中,free是不需要知道記憶體大小,只需傳入需要釋放的地址即可。為了在使用free時無需知道記憶體塊得大小也可以正確釋放記憶體塊,CosOS中採用的方法是,將記憶體塊得大小儲存在記憶體塊首地址前得一個整型空間中,具體實現如下://size為申請記憶體的大小void * malloc(u32int size){//使用alloc從堆中申請記憶體時,多申請4個位元組,用來儲存記憶體塊大小。         void *p= alloc(size + 4);//在返回記憶體塊的前4個位元組中(即一個整型中)儲存記憶體塊大小。         *((u32int*)p) = size;//返回這4個位元組之後的地址,防止使用記憶體塊時,大小被破壞。         return(void*)((u32int)p + 4);}void free(void *p){//從記憶體塊首地址的前4個位元組中擷取記憶體塊的大小,儲存在size中。         u32int size = *((u32int*)p - 1);//使用free_int釋放這塊記憶體。         free_int((u32int)p - 4, size + 4);} 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.