溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

libc2.23 malloc部分源碼分析

發布時間:2021-10-18 16:29:10 來源:億速云 閱讀:261 作者:iii 欄目:編程語言

這篇文章主要介紹“libc2.23 malloc部分源碼分析”,在日常操作中,相信很多人在libc2.23 malloc部分源碼分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”libc2.23 malloc部分源碼分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一、簡介

glibc 內部 malloc() 函數只是__libc_malloc() 函數的別名,而 __libc_malloc() 函數的工作又主要由 _int_malloc() 完成。

因此,分析malloc() 函數,

即是分析 __libc_malloc() 以及 _int_malloc() 這兩個函數。

2.24源碼

二、源碼與解析

1.__libc_malloc()

1.atomic_forced_read()函數

# define atomic_forced_read(x) 
               ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
       __typeof是原始函數的返回類型,后面是一段匯編代碼,”0”是零,即%0,引用時不可以加 %,
       只能input引用output,這里就是原子讀,將__malloc_hook的地址放入任意寄存器(r)再取出

2.關于malloc_hook的初始化問題

ptmalloc 定義了一個全局鉤子 __malloc_hook,這個鉤子會被賦值為 malloc_hook_ini 函數:(也就是說剛開始malloc_hook的值為malloc_hook_ini 函數的地址,第一次調用的時候會執行malloc_hook_ini )

void *weak_variable (*__malloc_hook)
  (size_t __size, const void *) = malloc_hook_ini;

如果我們需要自定義堆分配函數,那么就可以把 __malloc_hook 重新設置成我們自定義的函數,在 __libc_malloc 的最開始處會判斷是否調用 __malloc_hook。也就是說 ptmalloc 給我們提供了一個機會去使用自己定義的堆分配函數來完成對堆空間的申請,申請完成后直接返回,如下:

void *(*hook) (size_t, const void *)
    = atomic_forced_read (__malloc_hook);
  if (__builtin_expect (hook != NULL, 0))
    return (*hook)(bytes, RETURN_ADDRESS (0));

如果我們沒有自定義堆分配函數,而是選擇默認的 ptmalloc 來幫我們完成申請,那么在用戶在第一次調用 malloc 函數時會首先轉入 malloc_hook_ini 函數里面,這個函數的定義在 hook.c 文件,如下:

static void *
malloc_hook_ini (size_t sz, const void *caller)
{
  __malloc_hook = NULL;
  ptmalloc_init ();
  return __libc_malloc (sz);
}

可見在 malloc_hook_ini 會把 __malloc_hook 設置為空,然后調用 ptmalloc_init 函數,這個函數的工作是完成對 ptmalloc 的初始化,最后又重復調用 __libc_malloc 函數。

因此可知,在我們第一次調用 malloc 申請堆空間的時候,首先會進入 malloc_hook_ini 函數里面進行對 ptmalloc 的初始化工作,然后再次進入 __libc_malloc 的時候,此時鉤子 __malloc_hook 已經被置空了,從而繼續執行剩余的代碼,即轉入 _int_malloc 函數。

換個說法,第一次調用 malloc 函數時函數調用路徑如下:

malloc -> __libc_malloc -> __malloc_hook(即malloc_hook_ini) -> ptmalloc_init -> __libc_malloc -> _int_malloc

以后用戶再調用 malloc 函數的時候,路徑將是這樣的:

malloc -> __libc_malloc -> _int_mallocc

3.ptmalloc_init 函數

ptmalloc_init 的定義在 arena.c 文件里面,它里面有這樣的一些操作:

static void
ptmalloc_init (void)
{
  if (__malloc_initialized >= 0)
    return;

  __malloc_initialized = 0;

  // 初始化 ptmalloc 操作
  ...
  ...

  __malloc_initialized = 1;
}

進入 ptmalloc_init,首先判斷 __malloc_initialized 的值,__malloc_initialized 是一個全局變量,它標記著 ptcmalloc 的初始化狀態,如下:

>0 –> 初始化完成
=0 –> 正在初始化
<0 –> 尚未初始化

在 ptmalloc_init 中完成對 ptmalloc 的初始化工作后,置 __malloc_initialized 為 1,表示 ptmalloc 已經被初始化,之后再次進入 ptmalloc_init 時就會直接退出,不會重復初始化。

4.之后對源碼的解釋

void *
__libc_malloc (size_t bytes)//size_t bytes為我們用戶申請的大小
{
  mstate ar_ptr;
  void *victim;

  void *(*hook) (size_t, const void *)
    = atomic_forced_read (__malloc_hook);
  if (__builtin_expect (hook != NULL, 0))
    return (*hook)(bytes, RETURN_ADDRESS (0));

  arena_get (ar_ptr, bytes);
 //獲取當前的arena,如果是主線程則獲得的是main_arena
  victim = _int_malloc (ar_ptr, bytes);
    //進入_int_malloc函數
  /* Retry with another arena only if we were able to find a usable arena
     before.  */
  if (!victim && ar_ptr != NULL)
      //如果_int_malloc 分配失敗,并且我們之前能夠找到一個可用arena,可以用另一個arena重試。
    {
      LIBC_PROBE (memory_malloc_retry, 1, bytes);
      ar_ptr = arena_get_retry (ar_ptr, bytes);
      victim = _int_malloc (ar_ptr, bytes);
    }

  if (ar_ptr != NULL)
    (void) mutex_unlock (&ar_ptr->mutex);
 //釋放mutex引用的互斥鎖對象,因為ptmalloc支持多線程
  assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
          ar_ptr == arena_for_chunk (mem2chunk (victim)));
  return victim;
}
libc_hidden_def (__libc_malloc)

2._int_malloc()

/*
   ------------------------------ malloc ------------------------------
 */

static void *
_int_malloc (mstate av, size_t bytes)
{
  INTERNAL_SIZE_T nb;               /* normalized request size */
  unsigned int idx;                 /* associated bin index */
  mbinptr bin;                      /* associated bin */

  mchunkptr victim;                 /* inspected/selected chunk */
  INTERNAL_SIZE_T size;             /* its size */
  int victim_index;                 /* its bin index */

  mchunkptr remainder;              /* remainder from a split */
  unsigned long remainder_size;     /* its size */

  unsigned int block;               /* bit map traverser */
  unsigned int bit;                 /* bit map traverser */
  unsigned int map;                 /* current word of binmap */

  mchunkptr fwd;                    /* misc temp for linking */
  mchunkptr bck;                    /* misc temp for linking */

  const char *errstr = NULL;

  /*
     Convert request size to internal form by adding SIZE_SZ bytes
     overhead plus possibly more to obtain necessary alignment and/or
     to obtain a size of at least MINSIZE, the smallest allocatable
     size. Also, checked_request2size traps (returning 0) request sizes
     that are so large that they wrap around zero when padded and
     aligned.
   */

  checked_request2size (bytes, nb);
//這里將我們用戶申請的大小轉化為對應chunk的大小,nb就是我們轉化后的大小
  /* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
     mmap.  */
  if (__glibc_unlikely (av == NULL))
    {
      void *p = sysmalloc (nb, av);
      if (p != NULL)
    alloc_perturb (p, bytes);
      return p;
    }
////傳入的參數av是在上面__libc_malloc中調用arena_get獲得的分配去指針,如果為null,就表示沒有分配區可用,這時候就直接調用sysmalloc通過mmap獲取chunk
  /*
     If the size qualifies as a fastbin, first check corresponding bin.
     This code is safe to execute even if av is not yet initialized, so we
     can try it without checking, which saves some time on this fast path.
   */
//從 fastbin 中分配 chunk 
  if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
//get_max_fast返回fastbin可以存儲內存的最大值,它在ptmalloc的初始化函數malloc_init_state中定義。
//如果需要分配的內存大小nb落在fastbin的范圍內,我么嘗試從 fast bins 中 分配 chunk
    {
      idx = fastbin_index (nb);
/*
		加入我們的chunk大小是0x20(最小也是0x20),那么我們的索引就是(64位)
		1.0x20 >> 4 = 2
		2.2 -2 = 0
		3.idx = 0
        #define fastbin_index(sz) 
            ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
        減2是根據fastbin存儲的內存最小值計算的,32位為4,64位為8,假設SIZE_SZ=8,因此改寫后
        idx = (nb>>4)-2
    */
      mfastbinptr *fb = &fastbin (av, idx);
      //#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])
      //根據idx獲取對應鏈表的頭指針
      mchunkptr pp = *fb;//獲取對應大小的fatbin的鏈表中的第一個空閑的chunk
      do
        {
          victim = pp;
          if (victim == NULL)
            break;
        }
      while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
             != victim);
 //catomic_compare_and_exchange_val_rel 功能是 如果*fb等于victim,則將*fb存儲為victim->fd,返回victim;
//pp = victim == victim 導致循環退出
//作用為從剛剛得到的空閑chunk鏈表指針中取出第一個空閑的chunk(victim),并將鏈表頭設置為該空閑chunk的下一個chunk(victim->fd)
//此時victim是我們取出的chunk的地址
      if (victim != 0)
        {
          if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
 //這里是檢查我們取出的chunk的size所對應的索引是否等于我們之前已經得到的索引
 //其實這里就是在檢查我們取出的chunk的size是否與我們申請的fastbin的大小相同(這也是malloc的唯一檢查)
            {
              errstr = "malloc(): memory corruption (fast)";
            errout:
              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
              return NULL;
            }
          check_remalloced_chunk (av, victim, nb);
////# define check_remalloced_chunk(A, P, N)
          //check_remalloced_chunk 這個函數其他博客說什么也沒有實現
          void *p = chunk2mem (victim);//把chunk的指針轉換成mem的指針
          alloc_perturb (p, bytes);
         /*
           static void  alloc_perturb (char *p, size_t n)
           {
            if (__glibc_unlikely (perturb_byte))
               memset (p, perturb_byte ^ 0xff, n);
           }
        */
        /*這里就是向p(chunk的地址)+0x10填充字符(大小是我們申請的大?。?,但是貌似
        啥時候填充不知到,,就直接忽略把,其實啥也沒有發生*/
          return p;//反回我們的chunk
        }
    }

  /*
     If a small request, check regular bin.  Since these "smallbins"
     hold one size each, no searching within bins is necessary.
     (For a large request, we need to wait until unsorted chunks are
     processed to find best fit. But for small ones, fits are exact
     anyway, so we can check now, which is faster.)
   */
//如果在 fastbins 里面沒有找到滿足要求的空閑 chunk 或者 nb 不屬于 fastbins,并且 nb 屬于 smallbins
  if (in_smallbin_range (nb))
    {
      idx = smallbin_index (nb);
      /*
       #define smallbin_index(sz) (
        (SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))
        )
       如果是64位,size>>4就是smallbin_index,32位則是size>>3
    */
     //idx為獲取的索引指針
      bin = bin_at (av, idx);
//獲得索引idx后,就通過idx獲取對應的small bin鏈表表頭指針
      if ((victim = last (bin)) != bin)
//獲取對應鏈表的最后一個chunk為victim然后與bin進行比較,也就是和鏈表頭進行比較,如果比較的結果為相等,那么該鏈表為空,跳過下面部分,進入檢查整理unsorted bin的行列,若不相等,則進入下面的代碼
        {
          if (victim == 0) /* initialization check */
              //victim為0表示smallbin還未初始化
            malloc_consolidate (av);//調用malloc_consolidate完成初始化操作
          else
            {
              bck = victim->bk;
              //獲取此chunk的下一個chunk的地址
    	     if (__glibc_unlikely (bck->fd != victim))//small bin 采取先進先出的原則
        //這里檢查victim下一個chunk的fd是否與victim相等
        //這里也是small bin的唯一檢查
                {
                  errstr = "malloc(): smallbin double linked list corrupted";
                  goto errout;
                }
              set_inuse_bit_at_offset (victim, nb);
  /*     #define set_inuse(p)							      \
  ((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size |= PREV_INUSE
  */
              //此函數為將下一個物理地址相鄰的chunk的 inuse bit 為 1
              //size & ~SIZE_BITS,這個為size大小去掉標志位的結果,得到(p + (p)->size & ~SIZE_BITS))也就是說獲取相鄰物理地址下一個chunk的地址
              bin->bk = bck;
              bck->fd = bin;
    //雙向鏈表 bin->bk = bck;鏈表頭的bk為victim下一個chunk的地址
    // bck->fd = bin victim下一個chunk的fd設置為鏈表頭地址
              if (av != &main_arena)
                victim->size |= NON_MAIN_ARENA;//如果不是主線程則設置NON_MAIN_ARENA位
              check_malloced_chunk (av, victim, nb);//默認沒有做任何操作
              void *p = chunk2mem (victim);//這里就和之前相同了將chunk指針轉化為mem指針
              alloc_perturb (p, bytes);//默認不做任何操作
              return p;
            }
        }
    }

  /*
     If this is a large request, consolidate fastbins before continuing.
     While it might look excessive to kill all fastbins before
     even seeing if there is space available, this avoids
     fragmentation problems normally associated with fastbins.
     Also, in practice, programs tend to have runs of either small or
     large requests, but less often mixtures, so consolidation is not
     invoked all that often in most programs. And the programs that
     it is called frequently in otherwise tend to fragment.
   */

  else//這里就是我們申請的大小屬于large bin
    {
      idx = largebin_index (nb);//獲取對應大小的large bin的索引
      if (have_fastchunks (av))//這里是檢查fastbin鏈表是否為空,若為空就沒必要執行malloc_consolidate (av);來合并fastbin了,如果不為空則執行malloc_consolidate (av)
      //標記 fastbins 是否為空的是分配區管理的一個數據成員 flags,在 free 函數中當被釋放空間插入到 fastbins 中時這個數據成員被設置,在 malloc_consolidate 函數中整理 fastbins 時這個數據成員被清除。
           /*
        #define FASTCHUNKS_BIT        (1U)
        #define have_fastchunks(M)     (((M)->flags & FASTCHUNKS_BIT) == 0)
  
    */
        malloc_consolidate (av);
    }
//malloc_consolidate (av);函數:
/*fastbins中的chunk都整理到unsortedbin中,整理的過程中如果有物理相鄰且空閑的fastchunk就合并,如果fastchunk與topchunk相鄰,那么fastchunk就與topchunk合并(這個過程發生在_int_malloc函數調用的malloc_consolidate函數中)
     (注意這里是把fastbin中的所有塊清空)*/
  /*
     Process recently freed or remaindered chunks, taking one only if
     it is exact fit, or, if this a small request, the chunk is remainder from
     the most recent non-exact fit.  Place other traversed chunks in
     bins.  Note that this step is the only place in any routine where
     chunks are placed in bins.

     The outer loop here is needed because we might not realize until
     near the end of malloc that we should have consolidated, so must
     do so and retry. This happens at most once, and only when we would
     otherwise need to expand memory to service a "small" request.

   */

  for (;; )
    {
      int iters = 0;
      while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
          //如果沒有鏈表為空,那么unsorted_chunks (av)->bk) = unsorted_chunks (av) = main_arnea中的top
          //如果鏈表不為空,則循環遍歷所有的chunk
        {
          bck = victim->bk;
          if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
              || __builtin_expect (victim->size > av->system_mem, 0))
            malloc_printerr (check_action, "malloc(): memory corruption",
                             chunk2mem (victim), av);
          size = chunksize (victim);
          /*
         檢查當前遍歷的 chunk 是否合法,chunk 的大小不能小于等于 2 * SIZE_SZ,
         也不能超過 該分配區總的內存分配量。然后獲取 chunk 的大小并賦值給 size。
         這里的檢查似乎有點小問 題,直接使用了 victim->size,但 victim->size 
         中包含了相關的標志位信息,使用 chunksize(victim) 才比較合理,但在 
         unsorted bin 中的空閑 chunk 的所有標志位都清零了,所以這里直接 
         victim->size 沒有問題。
         */

          /*
             If a small request, try to use last remainder if it is the
             only chunk in unsorted bin.  This helps promote locality for
             runs of consecutive small requests. This is the only
             exception to best-fit, and applies only when there is
             no exact fit for a small chunk.
           */
    
          if (in_smallbin_range (nb) &&
              bck == unsorted_chunks (av) &&
              victim == av->last_remainder &&
              (unsigned long) (size) > (unsigned long) (nb + MINSIZE))
               /*
         如果要申請的大小在smallbin范圍 且 unsorted chunks 只有一個chunk,且
         victim是last_remainder 且 victim的size大于請求的chunk的大小nb加上
         (MINSIZE)最小chunk的size,那么就切割remainder,然后返回victim。
         即滿足四個條件:
         
       申請空間 nb 在 smallbins 范圍內
       unsortedbin 僅有唯一一個空閑 chunk
       唯一的一個空閑 chunk 是 last_remainder
       唯一一個空閑 chunk 的大小可以進行切割

         
		如果在bins鏈(不包括fastbin)中存在freechunk時,當我們去malloc的時候,malloc的請求大小比freechunk的大小小,那么arena就會切割這個freechunk給malloc使用,那么切割之后剩余的chunk就被稱為“last remainder”
當產生last remainder之后,表示arena的malloc_state結構體中的last_remainder成員指針就會被初始化,并且指向這個last remainder
     */
            {
              /* split and reattach remainder */
 //分割reminder,并將新的reminder插入到unsorted bin中
              remainder_size = size - nb;//計算剩下reminder的大小
              remainder = chunk_at_offset (victim, nb);//獲取剩下的reminder的地址
              unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder;//將新的reminder插入到unsorted bin中
              av->last_remainder = remainder;//last_reminder重新指向新的reminder
              remainder->bk = remainder->fd = unsorted_chunks (av);//新reminder的fd與bk指向unsorted bin 的鏈表頭,注意,unsorted bin鏈表頭并不是malloc_chunk結構體,而是main_arena變量中bins列表的前兩項分別做fd和bk指針,指向的位置也不是pre_size,而是main_arena中的top,top指向top chunk。
              if (!in_smallbin_range (remainder_size))
               //如果新的remind的size不在small bin中,而是在large bin中,那么將則把                                  fd_nextsize,fd_nextsize清零
                {
                  remainder->fd_nextsize = NULL;
                  remainder->bk_nextsize = NULL;
                }
    
              set_head (victim, nb | PREV_INUSE |
                        (av != &main_arena ? NON_MAIN_ARENA : 0));//設置victim的size
              set_head (remainder, remainder_size | PREV_INUSE);//設置remainder的size
              set_foot (remainder, remainder_size);//設置remainder的物理相鄰的下一個chunk的prev_size
    
              check_malloced_chunk (av, victim, nb);///默認沒有做任何操作
              void *p = chunk2mem (victim);//這里就和之前相同了將chunk指針轉化為mem指針
              alloc_perturb (p, bytes);//默認沒有做任何操作
              return p;
            }
    
          /* remove from unsorted list */
          unsorted_chunks (av)->bk = bck;
          bck->fd = unsorted_chunks (av);
    //將victim移除unsorted bin
          /* Take now instead of binning if exact fit */
    //下面是精確匹配,如果我們申請的大小轉化后正好等于victim size,直接返回即可
          if (size == nb)
            {
              set_inuse_bit_at_offset (victim, size);
              //設置victim物理相鄰的下一個chunk的prev_inuse位
              if (av != &main_arena)
                victim->size |= NON_MAIN_ARENA;
              //如果av不是main_arena 也就是說如果不是主進程,設置NON_MAIN_ARENA位
              check_malloced_chunk (av, victim, nb);//默認不做任何操作
              void *p = chunk2mem (victim);//這里就和之前相同了將chunk指針轉化為mem指針
              alloc_perturb (p, bytes);//默認不做任何操作
              return p;
            }
    
          /* place chunk in bin */
    //若上一個步驟沒有成功,則將victim置于對應的bin中
          if (in_smallbin_range (size))//如果victim的size大小為small bin
            {
              victim_index = smallbin_index (size);//獲取大小對應的索引
              bck = bin_at (av, victim_index);//宏 bin_at(m, i) 通過 bin index 獲得 bin 的鏈表頭,m 指的是分配區,i 是索引
              fwd = bck->fd;//FIFO原則 bck->fd 指向最新插入的chunk(small bin為頭插法)
            }
          else//若不在small bin的范圍中,則
            {
              victim_index = largebin_index (size);
              bck = bin_at (av, victim_index);
              fwd = bck->fd;//FIFO原則 bck->fd 指向最新插入的chunk(small bin為頭插法)
    
              /* maintain large bins in sorted order */
              if (fwd != bck)
                {
                  /* Or with inuse bit to speed comparisons */
                  size |= PREV_INUSE;
                  /* if smaller than smallest, bypass loop below */
                  assert ((bck->bk->size & NON_MAIN_ARENA) == 0);
                  if ((unsigned long) (size) < (unsigned long) (bck->bk->size))
                    {
                      fwd = bck;
                      bck = bck->bk;
    
                      victim->fd_nextsize = fwd->fd;
                      victim->bk_nextsize = fwd->fd->bk_nextsize;
                      fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
                    }
                  else
                    {
                      assert ((fwd->size & NON_MAIN_ARENA) == 0);
                      while ((unsigned long) size < fwd->size)
                        {
                          fwd = fwd->fd_nextsize;
                          assert ((fwd->size & NON_MAIN_ARENA) == 0);
                        }
    
                      if ((unsigned long) size == (unsigned long) fwd->size)
                        /* Always insert in the second position.  */
                        fwd = fwd->fd;
                      else
                        {
                          victim->fd_nextsize = fwd;
                          victim->bk_nextsize = fwd->bk_nextsize;
                          fwd->bk_nextsize = victim;
                          victim->bk_nextsize->fd_nextsize = victim;
                        }
                      bck = fwd->bk;
                    }
                }
              else
                victim->fd_nextsize = victim->bk_nextsize = victim;
            }
    
          mark_bin (av, victim_index);
          victim->bk = bck;
          victim->fd = fwd;
          fwd->bk = victim;
          bck->fd = victim;

#define MAX_ITERS       10000
          if (++iters >= MAX_ITERS)
            break;
        }

      /*
         If a large request, scan through the chunks of current bin in
         sorted order to find smallest that fits.  Use the skip list for this.
       */
    
      if (!in_smallbin_range (nb))
        {
          bin = bin_at (av, idx);
    
          /* skip scan if empty or largest chunk is too small */
          if ((victim = first (bin)) != bin &&
              (unsigned long) (victim->size) >= (unsigned long) (nb))
            {
              victim = victim->bk_nextsize;
              while (((unsigned long) (size = chunksize (victim)) <
                      (unsigned long) (nb)))
                victim = victim->bk_nextsize;
    
              /* Avoid removing the first entry for a size so that the skip
                 list does not have to be rerouted.  */
              if (victim != last (bin) && victim->size == victim->fd->size)
                victim = victim->fd;
    
              remainder_size = size - nb;
              unlink (av, victim, bck, fwd);
    
              /* Exhaust */
              if (remainder_size < MINSIZE)
                {
                  set_inuse_bit_at_offset (victim, size);
                  if (av != &main_arena)
                    victim->size |= NON_MAIN_ARENA;
                }
              /* Split */
              else
                {
                  remainder = chunk_at_offset (victim, nb);
                  /* We cannot assume the unsorted list is empty and therefore
                     have to perform a complete insert here.  */
                  bck = unsorted_chunks (av);
                  fwd = bck->fd;
      if (__glibc_unlikely (fwd->bk != bck))
                    {
                      errstr = "malloc(): corrupted unsorted chunks";
                      goto errout;
                    }
                  remainder->bk = bck;
                  remainder->fd = fwd;
                  bck->fd = remainder;
                  fwd->bk = remainder;
                  if (!in_smallbin_range (remainder_size))
                    {
                      remainder->fd_nextsize = NULL;
                      remainder->bk_nextsize = NULL;
                    }
                  set_head (victim, nb | PREV_INUSE |
                            (av != &main_arena ? NON_MAIN_ARENA : 0));
                  set_head (remainder, remainder_size | PREV_INUSE);
                  set_foot (remainder, remainder_size);
                }
              check_malloced_chunk (av, victim, nb);
              void *p = chunk2mem (victim);
              alloc_perturb (p, bytes);
              return p;
            }
        }
    
      /*
         Search for a chunk by scanning bins, starting with next largest
         bin. This search is strictly by best-fit; i.e., the smallest
         (with ties going to approximately the least recently used) chunk
         that fits is selected.
    
         The bitmap avoids needing to check that most blocks are nonempty.
         The particular case of skipping all bins during warm-up phases
         when no chunks have been returned yet is faster than it might look.
       */
    
      ++idx;
      bin = bin_at (av, idx);
      block = idx2block (idx);
      map = av->binmap[block];
      bit = idx2bit (idx);
    
      for (;; )
        {
          /* Skip rest of block if there are no more set bits in this block.  */
          if (bit > map || bit == 0)
            {
              do
                {
                  if (++block >= BINMAPSIZE) /* out of bins */
                    goto use_top;
                }
              while ((map = av->binmap[block]) == 0);
    
              bin = bin_at (av, (block << BINMAPSHIFT));
              bit = 1;
            }
    
          /* Advance to bin with set bit. There must be one. */
          while ((bit & map) == 0)
            {
              bin = next_bin (bin);
              bit <<= 1;
              assert (bit != 0);
            }
    
          /* Inspect the bin. It is likely to be non-empty */
          victim = last (bin);
    
          /*  If a false alarm (empty bin), clear the bit. */
          if (victim == bin)
            {
              av->binmap[block] = map &= ~bit; /* Write through */
              bin = next_bin (bin);
              bit <<= 1;
            }
    
          else
            {
              size = chunksize (victim);
    
              /*  We know the first chunk in this bin is big enough to use. */
              assert ((unsigned long) (size) >= (unsigned long) (nb));
    
              remainder_size = size - nb;
    
              /* unlink */
              unlink (av, victim, bck, fwd);
    
              /* Exhaust */
              if (remainder_size < MINSIZE)
                {
                  set_inuse_bit_at_offset (victim, size);
                  if (av != &main_arena)
                    victim->size |= NON_MAIN_ARENA;
                }
    
              /* Split */
              else
                {
                  remainder = chunk_at_offset (victim, nb);
    
                  /* We cannot assume the unsorted list is empty and therefore
                     have to perform a complete insert here.  */
                  bck = unsorted_chunks (av);
                  fwd = bck->fd;
      if (__glibc_unlikely (fwd->bk != bck))
                    {
                      errstr = "malloc(): corrupted unsorted chunks 2";
                      goto errout;
                    }
                  remainder->bk = bck;
                  remainder->fd = fwd;
                  bck->fd = remainder;
                  fwd->bk = remainder;
    
                  /* advertise as last remainder */
                  if (in_smallbin_range (nb))
                    av->last_remainder = remainder;
                  if (!in_smallbin_range (remainder_size))
                    {
                      remainder->fd_nextsize = NULL;
                      remainder->bk_nextsize = NULL;
                    }
                  set_head (victim, nb | PREV_INUSE |
                            (av != &main_arena ? NON_MAIN_ARENA : 0));
                  set_head (remainder, remainder_size | PREV_INUSE);
                  set_foot (remainder, remainder_size);
                }
              check_malloced_chunk (av, victim, nb);
              void *p = chunk2mem (victim);
              alloc_perturb (p, bytes);
              return p;
            }
        }
    
    use_top:
      /*
         If large enough, split off the chunk bordering the end of memory
         (held in av->top). Note that this is in accord with the best-fit
         search rule.  In effect, av->top is treated as larger (and thus
         less well fitting) than any other available chunk since it can
         be extended to be as large as necessary (up to system
         limitations).
    
         We require that av->top always exists (i.e., has size >=
         MINSIZE) after initialization, so if it would otherwise be
         exhausted by current request, it is replenished. (The main
         reason for ensuring it exists is that we may need MINSIZE space
         to put in fenceposts in sysmalloc.)
       */
    
      victim = av->top;
      size = chunksize (victim);
    
      if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
        {
          remainder_size = size - nb;
          remainder = chunk_at_offset (victim, nb);
          av->top = remainder;
          set_head (victim, nb | PREV_INUSE |
                    (av != &main_arena ? NON_MAIN_ARENA : 0));
          set_head (remainder, remainder_size | PREV_INUSE);
    
          check_malloced_chunk (av, victim, nb);
          void *p = chunk2mem (victim);
          alloc_perturb (p, bytes);
          return p;
        }
    
      /* When we are using atomic ops to free fast chunks we can get
         here for all block sizes.  */
      else if (have_fastchunks (av))
        {
          malloc_consolidate (av);
          /* restore original bin index */
          if (in_smallbin_range (nb))
            idx = smallbin_index (nb);
          else
            idx = largebin_index (nb);
        }
    
      /*
         Otherwise, relay to handle system-dependent cases
       */
      else
        {
          void *p = sysmalloc (nb, av);
          if (p != NULL)
            alloc_perturb (p, bytes);
          return p;
        }
    }

}

到此,關于“libc2.23 malloc部分源碼分析”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女