`
mqzhuang
  • 浏览: 185442 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Glibc内存管理--ptmalloc2源代码分析(三十)

阅读更多

5.7.2.5 malloc_consolidate()

malloc_consolidate() 函数用于将 fast bins 中的 chunk 合并,并加入 unsorted bin 中,其实现源代码如下:

/*
  ------------------------- malloc_consolidate -------------------------

  malloc_consolidate is a specialized version of free() that tears
  down chunks held in fastbins.  Free itself cannot be used for this
  purpose since, among other things, it might place chunks back onto
  fastbins.  So, instead, we need to use a minor variant of the same
  code.

  Also, because this routine needs to be called the first time through
  malloc anyway, it turns out to be the perfect place to trigger
  initialization code.
*/
#if __STD_C
static void malloc_consolidate(mstate av)
#else
static void malloc_consolidate(av) mstate av;
#endif
{
  mfastbinptr*    fb;                 /* current fastbin being consolidated */
  mfastbinptr*    maxfb;              /* last fastbin (for loop control) */
  mchunkptr       p;                  /* current chunk being consolidated */
  mchunkptr       nextp;              /* next chunk to consolidate */
  mchunkptr       unsorted_bin;       /* bin header */
  mchunkptr       first_unsorted;     /* chunk to link to */

  /* These have same use as in free() */
  mchunkptr       nextchunk;
  INTERNAL_SIZE_T size;
  INTERNAL_SIZE_T nextsize;
  INTERNAL_SIZE_T prevsize;
  int             nextinuse;
  mchunkptr       bck;
  mchunkptr       fwd;

  /*
    If max_fast is 0, we know that av hasn't
    yet been initialized, in which case do so below
  */
  if (get_max_fast () != 0) {
    clear_fastchunks(av);

    unsorted_bin = unsorted_chunks(av);

 如果全局变量 global_max_fast 不为零,表示 ptmalloc 已经初始化,清除分配区 flag fast bin 的标志位,该标志位表示分配区的 fast bins 中包含空闲 chunk 。然后获得分配区的 unsorted bin

    /*
      Remove each chunk from fast bin and consolidate it, placing it
      then in unsorted bin. Among other reasons for doing this,
      placing in unsorted bin avoids needing to calculate actual bins
      until malloc is sure that chunks aren't immediately going to be
      reused anyway.
    */

#if 0
    /* It is wrong to limit the fast bins to search using get_max_fast
       because, except for the main arena, all the others might have
       blocks in the high fast bins.  It's not worth it anyway, just
       search all bins all the time.  */
    maxfb = &fastbin (av, fastbin_index(get_max_fast ()));
#else
    maxfb = &fastbin (av, NFASTBINS - 1);
#endif
fb = &fastbin (av, 0);
将分配区最大的一个fast bin赋值给maxfb,第一个fast bin赋值给fb,然后遍历fast bins。

    do {
#ifdef ATOMIC_FASTBINS
      p = atomic_exchange_acq (fb, 0);
#else
      p = *fb;
#endif
      if (p != 0) {
#ifndef ATOMIC_FASTBINS
        *fb = 0;
#endif
获取当前遍历的fast bin中空闲chunk单向链表的头指针赋值给p,如果p不为0,将当前fast bin链表的头指针赋值为0,即删除了该fast bin中的空闲chunk链表。

        do {
          check_inuse_chunk(av, p);
          nextp = p->fd;
将空闲chunk链表的下一个chunk赋值给nextp。

          /* Slightly streamlined version of consolidation code in free() */
          size = p->size & ~(PREV_INUSE|NON_MAIN_ARENA);
          nextchunk = chunk_at_offset(p, size);
          nextsize = chunksize(nextchunk);
获得当前chunk的size,需要去除size中的PREV_INUSE和NON_MAIN_ARENA标志,并获取相邻的下一个chunk和下一个chunk的大小。

          if (!prev_inuse(p)) {
            prevsize = p->prev_size;
            size += prevsize;
            p = chunk_at_offset(p, -((long) prevsize));
            unlink(p, bck, fwd);
          }
如果当前chunk的前一个chunk空闲,则将当前chunk与前一个chunk合并成一个空闲chunk,由于前一个chunk空闲,则当前chunk的prev_size保存了前一个chunk的大小,计算出合并后的chunk大小,并获取前一个chunk的指针,将前一个chunk从空闲链表中删除。

          if (nextchunk != av->top) {
            nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
如果与当前chunk相邻的下一个chunk不是分配区的top chunk,查看与当前chunk相邻的下一个chunk是否处于inuse状态。

            if (!nextinuse) {
              size += nextsize;
              unlink(nextchunk, bck, fwd);
            } else
              clear_inuse_bit_at_offset(nextchunk, 0);
如果与当前chunk相邻的下一个chunk处于inuse状态,清除当前chunk的inuse状态,则当前chunk空闲了。否则,将相邻的下一个空闲chunk从空闲链表中删除,并计算当前chunk与下一个chunk合并后的chunk大小。

            first_unsorted = unsorted_bin->fd;
            unsorted_bin->fd = p;
            first_unsorted->bk = p;
将合并后的chunk加入unsorted bin的双向循环链表中。

            if (!in_smallbin_range (size)) {
              p->fd_nextsize = NULL;
              p->bk_nextsize = NULL;
            }
如果合并后的chunk属于large bin,将chunk的fd_nextsize和bk_nextsize设置为NULL,因为在unsorted bin中这两个字段无用。

            set_head(p, size | PREV_INUSE);
            p->bk = unsorted_bin;
            p->fd = first_unsorted;
            set_foot(p, size);
设置合并后的空闲chunk大小,并标识前一个chunk处于inuse状态,因为必须保证不能有两个相邻的chunk都处于空闲状态。然后将合并后的chunk加入unsorted bin的双向循环链表中。最后设置合并后的空闲chunk的foot,chunk空闲时必须设置foot,该foot处于下一个chunk的prev_size中,只有chunk空闲是foot才是有效的。
          }
          else {
            size += nextsize;
            set_head(p, size | PREV_INUSE);
            av->top = p;
          }
如果当前chunk的下一个chunk为top chunk,则将当前chunk合并入top chunk,修改top chunk的大小。
        } while ( (p = nextp) != 0);
直到遍历完当前fast bin中的所有空闲chunk。
      }
} while (fb++ != maxfb);
直到遍历完所有的fast bins。
  }
  else {
    malloc_init_state(av);
check_malloc_state(av);
如果ptmalloc没有初始化,初始化ptmalloc。
  }
}
 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics