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

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

阅读更多

5.8.3 sYSTRIm()和munmap_chunk()

sYSTRIm() 函数源代码如下:

/*
  sYSTRIm is an inverse of sorts to sYSMALLOc.  It gives memory back
  to the system (via negative arguments to sbrk) if there is unused
  memory at the `high' end of the malloc pool. It is called
  automatically by free() when top space exceeds the trim
  threshold. It is also called by the public malloc_trim routine.  It
  returns 1 if it actually released any memory, else 0.
*/
#if __STD_C
static int sYSTRIm(size_t pad, mstate av)
#else
static int sYSTRIm(pad, av) size_t pad; mstate av;
#endif
{
  long  top_size;        /* Amount of top-most memory */
  long  extra;           /* Amount to release */
  long  released;        /* Amount actually released */
  char* current_brk;     /* address returned by pre-check sbrk call */
  char* new_brk;         /* address returned by post-check sbrk call */
  size_t pagesz;

  pagesz = mp_.pagesize;
  top_size = chunksize(av->top);
获取页大小也top chunk的大小。

  /* Release in pagesize units, keeping at least one page */
  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
计算top chunk中最大可释放的整数页大小,top chunk中至少需要MINSIZE的内存保存fencepost。

  if (extra > 0) {
    /*
      Only proceed if end of memory is where we last set it.
      This avoids problems if there were foreign sbrk calls.
    */
    current_brk = (char*)(MORECORE(0));
    if (current_brk == (char*)(av->top) + top_size) {
获取当前brk值,如果当前top chunk的结束地址与当前的brk值相等,执行heap收缩。

      /*
        Attempt to release memory. We ignore MORECORE return value,
        and instead call again to find out where new end of memory is.
        This avoids problems if first call releases less than we asked,
        of if failure somehow altered brk value. (We could still
        encounter problems if it altered brk in some very bad way,
        but the only thing we can do is adjust anyway, which will cause
        some downstream failure.)
      */
      MORECORE(-extra);
调用sbrk()释放指定大小的内存到heap中。

      /* Call the `morecore' hook if necessary.  */
      void (*hook) (void) = force_reg (__after_morecore_hook);
      if (__builtin_expect (hook != NULL, 0))
        (*hook) ();
      new_brk = (char*)(MORECORE(0));
如果morecore hook存在,执行hook函数,然后获得当前新的brk值。

      if (new_brk != (char*)MORECORE_FAILURE) {
        released = (long)(current_brk - new_brk);

        if (released != 0) {
          /* Success. Adjust top. */
          av->system_mem -= released;
          set_head(av->top, (top_size - released) | PREV_INUSE);
          check_malloc_state(av);
          return 1;
如果获取新的brk值成功,计算释放的内存大小,更新当前分配区所分配的内存总量,更新top chunk的大小。

        }
      }
    }
  }
  return 0;
}

 Munmap_chunk() 函数源代码如下:

static void
internal_function
#if __STD_C
munmap_chunk(mchunkptr p)
#else
munmap_chunk(p) mchunkptr p;
#endif
{
  INTERNAL_SIZE_T size = chunksize(p);

  assert (chunk_is_mmapped(p));
#if 0
  assert(! ((char*)p >= mp_.sbrk_base && (char*)p < mp_.sbrk_base + mp_.sbrked_mem));
  assert((mp_.n_mmaps > 0));
#endif

  uintptr_t block = (uintptr_t) p - p->prev_size;
  size_t total_size = p->prev_size + size;
  /* Unfortunately we have to do the compilers job by hand here.  Normally
     we would test BLOCK and TOTAL-SIZE separately for compliance with the
     page size.  But gcc does not recognize the optimization possibility
     (in the moment at least) so we combine the two values into one before
     the bit test.  */
  if (__builtin_expect (((block | total_size) & (mp_.pagesize - 1)) != 0, 0))
    {
      malloc_printerr (check_action, "munmap_chunk(): invalid pointer",
                       chunk2mem (p));
      return;
    }

  mp_.n_mmaps--;
  mp_.mmapped_mem -= total_size;

  int ret __attribute__ ((unused)) = munmap((char *)block, total_size);

  /* munmap returns non-zero on failure */
  assert(ret == 0);
}

 Munmap_chunk() 函数实现相当简单,首先获取当前 free chunk 的大小,断言当前 free chunk 是通过 mmap() 分配的,由于使用 mmap() 分配的 chunk prev_size 中记录的前一个相邻空闲 chunk 的大小, mmap() 分配的内存是页对齐的,所以一般情况下 prev_size 0 。然后计算当前 free chunk 占用的总内存大小 total_size ,再次校验内存块的起始地址是否是对齐的,更新分配区的 mmap 统计信息,最后调用 munmap() 函数释放 chunk 的内存。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics