青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

鍵盤的詠嘆調

常用鏈接

統計

最新評論

[zz]漫談malloc的實現

         malloc()是C語言中動態存儲管理的一組標準庫函數之一。其作用是在內存的動態存儲區中分配一個長度為size的連續空間。其參數是一個無符號整形數,返回值是一個指向所分配的連續存儲域的起始地址的指針。

   動態內存分配就是指在程序執行的過程中動態地分配或者回收存儲空間的分配內存的方法。動態內存分配不像數組等靜態內存分配方法那樣需要預先分配存儲空間,而是由系統根據程序的需要即時分配,且分配的大小就是程序要求的大小。本文簡單介紹動態內存分配函數malloc()及幾種實現方法。

   1. 簡介

  malloc()是C語言中動態存儲管理的一組標準庫函數之一。其作用是在內存的動態存儲區中分配一個長度為size的連續空間。其參數是一個無符號整形數,返回值是一個指向所分配的連續存儲域的起始地址的指針。還有一點必須注意的是,當函數未能成功分配存儲空間(如內存不足)就會返回一個NULL指針。所以在調用該函數時應該檢測返回值是否為NULL并執行相應的操作。

   2. 函數說明

  C語言的動態存儲管理由一組標準庫函數實現,其原型在標準文件<stdlib.h>里描述,需要用這些功能時應包含這個文件。與動態存儲分配有關的函數共有四個,其中就包括存儲分配函數malloc()。函數原型是:void *malloc (size_t n);這里的size_t是標準庫里定義的一個類型,它是一個無符號整型。這個整型能夠滿足所有對存儲塊大小描述的需要,具體相當于哪個整型由具體的C系統確定。malloc的返回值為(void *)類型(這是通用指針的一個重要用途),它分配一片能存放大小為n的數據的存儲塊,返回對應的指針值;如果不能滿足申請(找不到能滿足要求的存儲塊)就返回NULL。在使用時,應該把malloc的返回值轉換到特定指針類型,賦給一個指針。

    注意,雖然這里的存儲塊是通過動態分配得到的,但是它的大小也是確定的,同樣不允許越界使用。例如上面程序段分配的塊里能存n個雙精度數據,隨后的使用就必須在這個范圍內進行。越界使用動態分配的存儲塊,尤其是越界賦值,可能引起非常嚴重的后果,通常會破壞程序的運行系統,可能造成本程序或者整個計算機系統垮臺。

  下例是一個動態分配的例子:
#include <stdlib.h>

main()
{
 int count,*array; /*count是一個計數器,array是一個整型指針,也可以理解為指向一個整型數組的首地址*/
 if((array(int *) malloc (10*sizeof(int)))==NULL)
 {
  printf("不能成功分配存儲空間。");
  exit(1);
 }
 for (count=0;count〈10;count++) /*給數組賦值*/
  array[count]=count;
 for(count=0;count〈10;count++) /*打印數組元素*/
  printf("%2d",array[count]);
}

  上例中動態分配了10個整型存儲區域,然后進行賦值并打印。例中if((array(int *) malloc (10*sizeof(int)))==NULL)語句可以分為以下幾步:
  1)分配10個整型的連續存儲空間,并返回一個指向其起始地址的整型指針
  2)把此整型指針地址賦給array
  3)檢測返回值是否為NULL

   3. malloc()工作機制

  malloc函數的實質體現在,它有一個將可用的內存塊連接為一個長長的列表的所謂空閑鏈表。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然后,將該內存塊一分為二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,并將剩下的那塊(如果有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閑鏈上。到最后,空閑鏈會被切成很多的小內存片段,如果這時用戶申請一個大的內存片段,那么空閑鏈上可能沒有可以滿足用戶要求的片段了。于是,malloc函數請求延時,并開始在空閑鏈上翻箱倒柜地檢查各內存片段,對它們進行整理,將相鄰的小空閑塊合并成較大的內存塊。

   4. malloc()在操作系統中的實現

  在 C 程序中,多次使用malloc () 和 free()。不過,您可能沒有用一些時間去思考它們在您的操作系統中是如何實現的。本節將向您展示 malloc 和 free 的一個最簡化實現的代碼,來幫助說明管理內存時都涉及到了哪些事情。

  在大部分操作系統中,內存分配由以下兩個簡單的函數來處理:

  void *malloc (long numbytes):該函數負責分配 numbytes 大小的內存,并返回指向第一個字節的指針。

  void free(void *firstbyte):如果給定一個由先前的 malloc 返回的指針,那么該函數會將分配的空間歸還給進程的“空閑空間”。

  malloc_init 將是初始化內存分配程序的函數。它要完成以下三件事:將分配程序標識為已經初始化,找到系統中最后一個有效內存地址,然后建立起指向我們管理的內存的指針。這三個變量都是全局變量:

  清單 1. 我們的簡單分配程序的全局變量

        int has_initialized = 0;
        void *managed_memory_start;
        void *last_valid_address;

  如前所述,被映射的內存的邊界(最后一個有效地址)常被稱為系統中斷點或者 當前中斷點。在很多 UNIX? 系統中,為了指出當前系統中斷點,必須使用 sbrk(0) 函數。 sbrk 根據參數中給出的字節數移動當前系統中斷點,然后返回新的系統中斷點。使用參數 0 只是返回當前中斷點。這里是我們的 malloc 初始化代碼,它將找到當前中斷點并初始化我們的變量:

  清單 2. 分配程序初始化函數
/* Include the sbrk function */
 
#include
void malloc_init()
{
/* grab the last valid address from the OS */
last_valid_address = sbrk(0);
/* we don't have any memory to manage yet, so
 *just set the beginning to be last_valid_address
 */
managed_memory_start = last_valid_address;
/* Okay, we're initialized and ready to go */
 has_initialized = 1;
}

  現在,為了完全地管理內存,我們需要能夠追蹤要分配和回收哪些內存。在對內存塊進行了 free 調用之后,我們需要做的是諸如將它們標記為未被使用的等事情,并且,在調用 malloc 時,我們要能夠定位未被使用的內存塊。因此, malloc 返回的每塊內存的起始處首先要有這個結構:

  清單 3. 內存控制塊結構定義
struct mem_control_block {
int is_available;
int size;
};
   

   現在,您可能會認為當程序調用 malloc 時這會引發問題 —— 它們如何知道這個結構?答案是它們不必知道;在返回指針之前,我們會將其移動到這個結構之后,把它隱藏起來。這使得返回的指針指向沒有用于任何其他用途的內存。那樣,從調用程序的角度來看,它們所得到的全部是空閑的、開放的內存。然后,當通過 free() 將該指針傳遞回來時,我們只需要倒退幾個內存字節就可以再次找到這個結構。

  在討論分配內存之前,我們將先討論釋放,因為它更簡單。為了釋放內存,我們必須要做的惟一一件事情就是,獲得我們給出的指針,回退 sizeof(struct mem_control_block) 個字節,并將其標記為可用的。這里是對應的代碼:

  清單 4. 解除分配函數
void free(void *firstbyte) {
struct mem_control_block *mcb;
/* Backup from the given pointer to find the
 * mem_control_block
 */
mcb = firstbyte - sizeof(struct mem_control_block);
/* Mark the block as being available */
mcb->is_available = 1;
/* That's It!  We're done. */
return;
}

  如您所見,在這個分配程序中,內存的釋放使用了一個非常簡單的機制,在固定時間內完成內存釋放。分配內存稍微困難一些。以下是該算法的略述:

  清單 5. 主分配程序的偽代碼
1. If our allocator has not been initialized, initialize it.
2. Add sizeof(struct mem_control_block) to the size requested.
3. start at managed_memory_start.
4. Are we at last_valid address?
5. If we are:
   A. We didn't find any existing space that was large enough
      -- ask the operating system for more and return that.
6. Otherwise:
   A. Is the current space available (check is_available from
      the mem_control_block)?
   B. If it is:
      i)   Is it large enough (check "size" from the
           mem_control_block)?
      ii)  If so:
           a. Mark it as unavailable
           b. Move past mem_control_block and return the
              pointer
      iii) Otherwise:
           a. Move forward "size" bytes
           b. Go back go step 4
   C. Otherwise:
      i)   Move forward "size" bytes
      ii)  Go back to step 4

  我們主要使用連接的指針遍歷內存來尋找開放的內存塊。這里是代碼:

  清單 6. 主分配程序
void *malloc(long numbytes) {
/* Holds where we are looking in memory */
void *current_location;
/* This is the same as current_location, but cast to a
 * memory_control_block
 */
struct mem_control_block *current_location_mcb;
/* This is the memory location we will return.  It will
 * be set to 0 until we find something suitable
 */
void *memory_location;
/* Initialize if we haven't already done so */
if(! has_initialized) {
malloc_init();
}
/* The memory we search for has to include the memory
 * control block, but the users of malloc don't need
 * to know this, so we'll just add it in for them.
 */
numbytes = numbytes + sizeof(struct mem_control_block);
/* Set memory_location to 0 until we find a suitable
 * location
 */
memory_location = 0;
/* Begin searching at the start of managed memory */
current_location = managed_memory_start;
/* Keep going until we have searched all allocated space */
while(current_location != last_valid_address)
{
/* current_location and current_location_mcb point
 * to the same address.  However, current_location_mcb
 * is of the correct type, so we can use it as a struct.
 * current_location is a void pointer so we can use it
 * to calculate addresses.
 */
current_location_mcb =
(struct mem_control_block *)current_location;
if(current_location_mcb->is_available)
{
if(current_location_mcb->size >= numbytes)
{
/* Woohoo!  We've found an open,
 * appropriately-size location.
 */
/* It is no longer available */
current_location_mcb->is_available = 0;
/* We own it */
memory_location = current_location;
/* Leave the loop */
break;
}
}
/* If we made it here, it's because the Current memory
 * block not suitable; move to the next one
 */
current_location = current_location +
current_location_mcb->size;
}
/* If we still don't have a valid location, we'll
 * have to ask the operating system for more memory
 */
if(! memory_location)
{
/* Move the program break numbytes further */
sbrk(numbytes);
/* The new memory will be where the last valid
 * address left off
 */
memory_location = last_valid_address;
/* We'll move the last valid address forward
 * numbytes
 */
last_valid_address = last_valid_address + numbytes;
/* We need to initialize the mem_control_block */
current_location_mcb = memory_location;
current_location_mcb->is_available = 0;
current_location_mcb->size = numbytes;
}
/* Now, no matter what (well, except for error conditions),
 * memory_location has the address of the memory, including
 * the mem_control_block
 */
/* Move the pointer past the mem_control_block */
memory_location = memory_location + sizeof(struct mem_control_block);
/* Return the pointer */
return memory_location;
 }

  這就是我們的內存管理器。現在,我們只需要構建它,并在程序中使用它即可。
 

  5. malloc()的其他實現

  malloc() 的實現有很多,這些實現各有優點與缺點。在設計一個分配程序時,要面臨許多需要折衷的選擇,其中包括:

分配的速度。
回收的速度。
有線程的環境的行為。
內存將要被用光時的行為。
局部緩存。
簿記(Bookkeeping)內存開銷。
虛擬內存環境中的行為。
小的或者大的對象。
實時保證。
每一個實現都有其自身的優缺點集合。在我們的簡單的分配程序中,分配非常慢,而回收非???。另外,由于它在使用虛擬內存系統方面較差,所以它最適于處理大的對象。

  還有其他許多分配程序可以使用。其中包括:

  Doug Lea Malloc:Doug Lea Malloc 實際上是完整的一組分配程序,其中包括 Doug Lea 的原始分配程序,GNU libc 分配程序和 ptmalloc。 Doug Lea 的分配程序有著與我們的版本非常類似的基本結構,但是它加入了索引,這使得搜索速度更快,并且可以將多個沒有被使用的塊組合為一個大的塊。它還支持緩存,以便更快地再次使用最近釋放的內存。 ptmalloc 是 Doug Lea Malloc 的一個擴展版本,支持多線程。在本文后面的 參考資料部分中,有一篇描述 Doug Lea 的 Malloc 實現的文章。

  BSD Malloc:BSD Malloc 是隨 4.2 BSD 發行的實現,包含在 FreeBSD 之中,這個分配程序可以從預先確實大小的對象構成的池中分配對象。它有一些用于對象大小的 size 類,這些對象的大小為 2 的若干次冪減去某一常數。所以,如果您請求給定大小的一個對象,它就簡單地分配一個與之匹配的 size 類。這樣就提供了一個快速的實現,但是可能會浪費內存。在 參考資料部分中,有一篇描述該實現的文章。

  Hoard:編寫 Hoard 的目標是使內存分配在多線程環境中進行得非常快。因此,它的構造以鎖的使用為中心,從而使所有進程不必等待分配內存。它可以顯著地加快那些進行很多分配和回收的多線程進程的速度。在 參考資料部分中,有一篇描述該實現的文章。
眾多可用的分配程序中最有名的就是上述這些分配程序。如果您的程序有特別的分配需求,那么您可能更愿意編寫一個定制的能匹配您的程序內存分配方式的分配程序。不過,如果不熟悉分配程序的設計,那么定制分配程序通常會帶來比它們解決的問題更多的問題。

   6. 結束語

  前面已經提過,多次調用malloc()后空閑內存被切成很多的小內存片段,這就使得用戶在申請內存使用時,由于找不到足夠大的內存空間,malloc()需要進行內存整理,使得函數的性能越來越低。聰明的程序員通過總是分配大小為2的冪的內存塊,而最大限度地降低潛在的malloc性能喪失。也就是說,所分配的內存塊大小為4字節、8字節、16字節、18446744073709551616字節,等等。這樣做最大限度地減少了進入空閑鏈的怪異片段(各種尺寸的小片段都有)的數量。盡管看起來這好像浪費了空間,但也容易看出浪費的空間永遠不會超過50%。

   參考文獻:

  [1]  Jonathan Bartlett,內存管理內幕. developerWorks 中國,2004年11月

posted on 2009-01-25 13:13 鍵盤的詠嘆調 閱讀(672) 評論(0)  編輯 收藏 引用 所屬分類: C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美激情一区二区| 国产免费一区二区三区香蕉精| 免费看成人av| 亚洲欧美日韩在线高清直播| 亚洲激情专区| 曰韩精品一区二区| 精品福利电影| 最新国产拍偷乱拍精品| 亚洲国产成人av| 亚洲精品乱码久久久久久蜜桃91| 国内精品久久久| 亚洲国产日韩一级| 一区二区三区精品国产| 亚洲性人人天天夜夜摸| 午夜精品区一区二区三| 免费成人你懂的| 欧美大片第1页| 欧美亚一区二区| 国产日韩亚洲欧美精品| 在线观看不卡av| 亚洲午夜精品一区二区| 久久精品系列| 亚洲精品一区在线观看香蕉| 中文国产成人精品| 久久人人精品| 国产视频在线观看一区二区三区 | 麻豆国产精品一区二区三区 | 久久人人爽人人爽爽久久| 欧美丰满少妇xxxbbb| 亚洲天堂av在线免费观看| 久久精品一本久久99精品| 欧美亚州一区二区三区| 亚洲美女视频| 亚洲国产精品成人综合| 亚洲一区二区三区四区视频| 免费成人高清| 亚洲国产高清一区| 免费不卡视频| 久久躁日日躁aaaaxxxx| 影音先锋久久| 欧美国产一区在线| 欧美freesex交免费视频| 亚洲国产精品999| 欧美搞黄网站| 免费成人av在线| 一区二区激情视频| 国产免费亚洲高清| 久久久亚洲成人| 欧美在线一二三区| 亚洲国产成人不卡| 亚洲国产成人在线| 欧美激情精品久久久久久久变态| 亚洲精品欧洲精品| 在线视频亚洲欧美| 一区在线影院| 亚洲欧洲综合另类在线| 欧美日韩一区二区三区在线看 | 免费在线成人| 亚洲欧美www| 牛人盗摄一区二区三区视频| 亚洲免费伊人电影在线观看av| 午夜激情亚洲| 日韩午夜三级在线| 久久国产免费看| 国产精品99久久久久久宅男| 亚洲综合精品四区| 亚洲国产成人久久综合一区| 亚洲欧美日本精品| 在线视频亚洲欧美| 免费国产自线拍一欧美视频| 亚洲综合大片69999| 欧美激情精品久久久久| 欧美成人免费在线观看| 国产中文一区二区| 性伦欧美刺激片在线观看| 亚洲一区二区少妇| 欧美国产一区二区在线观看| 久久一区二区三区四区| 国产精品免费网站在线观看| 国产专区综合网| 亚洲欧美日韩精品一区二区| 亚洲综合成人在线| 国产美女扒开尿口久久久| 亚洲影音一区| 久久久久久九九九九| 伊人久久久大香线蕉综合直播| 欧美影院在线| 欧美国产欧美亚州国产日韩mv天天看完整| 国产精品亚洲аv天堂网| 久久精品国语| 亚洲人精品午夜| 亚洲欧美视频在线观看视频| 国产一区二区三区久久久| 免费观看成人| 亚洲一区二区三区四区中文 | 亚洲电影第1页| 欧美高清你懂得| 中国女人久久久| 亚洲观看高清完整版在线观看| 一区二区欧美日韩| 国内精品久久久久久| 欧美精品在线观看91| 亚洲一区在线播放| 亚洲在线一区二区| 久久亚洲私人国产精品va媚药| 欧美日韩在线播放| 久久久久成人网| 欧美精品综合| 久久都是精品| 亚洲欧美三级在线| 日韩午夜在线| 亚洲电影在线观看| 欧美亚洲综合另类| 在线视频精品| 在线视频欧美日韩精品| 亚洲人成在线免费观看| 亚洲欧洲av一区二区三区久久| 欧美激情亚洲激情| 欧美国产极速在线| 欧美高清在线精品一区| 欧美aⅴ一区二区三区视频| 久久久噜噜噜久久久| 久久精品综合| 欧美国产免费| 亚洲视频高清| 欧美一区二区在线看| 欧美在线观看视频在线| 欧美一区二区三区免费观看| av不卡在线观看| 性色一区二区| 欧美福利小视频| 欧美涩涩网站| 国产欧美日韩精品丝袜高跟鞋 | 亚洲第一精品福利| 亚洲欧洲精品一区二区三区波多野1战4 | 亚洲午夜激情在线| 亚洲自拍电影| 老司机免费视频久久| 亚洲春色另类小说| 日韩视频中午一区| 久久久久久一区| 国产精品久久网站| 亚洲国产日本| 久久夜色撩人精品| 午夜精品福利一区二区蜜股av| 美日韩免费视频| 国内视频精品| 久久久精彩视频| 性18欧美另类| 好看的日韩av电影| 亚洲美女一区| 性视频1819p久久| 欧美国产在线电影| 欧美在线播放高清精品| 国产精品亚洲人在线观看| 在线一区日本视频| 在线亚洲一区| 国产女人精品视频| 亚洲女优在线| 亚洲男女毛片无遮挡| 国产精品www.| 亚洲综合99| 香蕉乱码成人久久天堂爱免费| 欧美日本韩国一区二区三区| 日韩视频永久免费| 亚洲高清免费在线| 免费日韩av电影| 中国成人在线视频| 亚洲免费不卡| 国产日韩欧美中文| 男男成人高潮片免费网站| 午夜精品久久久久久99热软件| 国产欧美日本| 亚洲电影一级黄| 欧美色图五月天| 久久爱www久久做| 欧美乱妇高清无乱码| 午夜久久久久久| 欧美国产日韩精品| 久久精品日韩一区二区三区| 久久人人97超碰国产公开结果 | 欧美精品国产一区二区| 亚洲天堂第二页| 老司机精品视频一区二区三区| 夜久久久久久| 欧美另类videos死尸| 亚洲一区国产| 在线电影国产精品| 亚洲一区免费| 亚洲一区观看| 欧美国产日产韩国视频| 欧美成人精品一区二区三区| 国产精品国产三级国产a| 久久综合久久久久88| 国产精品伦子伦免费视频| 亚洲九九精品| 久久久午夜精品| 久久成人在线| 好吊色欧美一区二区三区四区| 亚洲女性喷水在线观看一区|