网站首页 Cn029.Com - 西安网吧在线℡

Cn029.Com - 西安网吧在线℡ 西北地区网吧行业门户站点www.cn029.com,本站为您提供网吧维护,每日更新最新网吧技术,政策法规.为您提供各类网管软件,网吧软件,游戏更新软件,承接西部地区网吧维护,希望与您共同讨论网吧经营管理的经验!

投递文章  投稿指南 RSS订阅 西安网吧在线通告:
搜索: 您的位置西安网吧在线Linux-UxLinux精华 → 文章内容

Uclibc中的malloc机制分析(五)

  作者:网络收集   来源:chinaunix.net   更新时间:2008-4-27 5:04:28   【 】  评论:0

六:free的实现:
这里有个值得注意的地方:如果合并的内存区大于一个阀值,必须要把它还给内核,以节约内存。具体的见下面的分析:
void
free (void *mem)
{
  free_to_heap (mem, &__malloc_heap);
}
跟踪进free_to_heap:
static void
free_to_heap (void *mem, struct heap *heap)
{
  size_t size;
  struct heap_free_area *fa;

//参数检查
  if (unlikely (! mem))
    return;

  MALLOC_DEBUG (1, "free: 0x%lx (base = 0x%lx, total_size = %d)",
                   (long)mem, (long)MALLOC_BASE (mem), MALLOC_SIZE (mem));
//这两个宏在上面已经分析过了
  size = MALLOC_SIZE (mem);
  mem = MALLOC_BASE (mem);

  __heap_lock (heap);
         //把释放的内存加入heap
  fa = __heap_free (heap, mem, size);


   //如果FA中的空闲区超过  MALLOC_UNMAP_THRESHOLD。就要进行内存回收了
         // MALLOC_UNMAP_THRESHOLD在代码中被定义成8个页面大小
  if (HEAP_FREE_AREA_SIZE (fa)
    /* Nope, nothing left to do, just release the lock.  */
    __heap_unlock (heap);
  else
   {
         //计算起始地址
      unsigned long start = (unsigned long)HEAP_FREE_AREA_START (fa);
    //计算结束地址
unsigned long end = (unsigned long)HEAP_FREE_AREA_END (fa);

//下面是sbrk,unmap两种方式的内存回收。这里不详细讨论。请关注本站的后续更新
#ifndef MALLOC_USE_SBRK
# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
      struct malloc_mmb *mmb, *prev_mmb;
      unsigned long mmb_start, mmb_end;
# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
      unsigned long unmap_start, unmap_end;
# endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
#endif /* !MALLOC_USE_SBRK */

#ifdef MALLOC_USE_SBRK
     
      if ((void *)end != sbrk (0))
         {
           MALLOC_DEBUG (-1, "not unmapping: 0x%lx - 0x%lx (%ld bytes)",
                            start, end, end - start);
           __malloc_unlock_sbrk ();
           __heap_unlock (heap);
           return;
         }
#endif

      MALLOC_DEBUG (0, "unmapping: 0x%lx - 0x%lx (%ld bytes)",
                       start, end, end - start);

      /* Remove FA from the heap.  */
          __heap_delete (heap, fa);

      if (__heap_is_empty (heap))
         
         {
           /* Put the reserved memory back in the heap; we asssume that
              MALLOC_UNMAP_THRESHOLD is greater than MALLOC_MIN_SIZE, so
              we use the latter unconditionally here.  */
           __heap_free (heap, (void *)start, MALLOC_MIN_SIZE);
           start += MALLOC_MIN_SIZE;
         }

#ifdef MALLOC_USE_SBRK

      /* Release the heap lock; we're still holding the sbrk lock.  */
      __heap_unlock (heap);
      /* Lower the brk.  */
      sbrk (start - end);
      /* Release the sbrk lock too; now we hold no locks.  */
      __malloc_unlock_sbrk ();

#else /* !MALLOC_USE_SBRK */

# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
         MALLOC_MMB_DEBUG (1, "walking mmb list for region 0x%x[%d]...",
                            start, end - start);

      prev_mmb = 0;
      mmb = __malloc_mmapped_blocks;
      while (mmb
              && ((mmb_end = (mmb_start = (unsigned long)mmb->mem) + mmb->size)
                    
         {
           MALLOC_MMB_DEBUG (1, "considering mmb at 0x%x: 0x%x[%d]",
                                (unsigned)mmb, mmb_start, mmb_end - mmb_start);

           if (mmb_start >= start
               && (start == mmb_start
                     || mmb_start - start > HEAP_MIN_FREE_AREA_SIZE))
             {
               struct malloc_mmb *next_mmb = mmb->next;

               if (mmb_end != end && mmb_end + HEAP_MIN_FREE_AREA_SIZE > end)
                   /* There's too little space left at the end to deallocate
                      this block, so give up.  */
                   break;

               MALLOC_MMB_DEBUG (1, "unmapping mmb at 0x%x: 0x%x[%d]",
                                     (unsigned)mmb, mmb_start, mmb_end - mmb_start);

               if (mmb_start != start)
                   /* We're going to unmap a part of the heap that begins after
                      start, so put the intervening region back into the heap.  */
                   {
                     MALLOC_MMB_DEBUG (0, "putting intervening region back into heap: 0x%x[%d]",
                                         start, mmb_start - start);
                     __heap_free (heap, (void *)start, mmb_start - start);
                   }

               MALLOC_MMB_DEBUG_INDENT (-1);

               /* Unlink MMB from the list.  */
               if (prev_mmb)
                   prev_mmb->next = next_mmb;
               else
                   __malloc_mmapped_blocks = next_mmb;

               /* Start searching again from the end of this block.  */
               start = mmb_end;
        __heap_unlock (heap);

               /* Release the descriptor block we used.  */
                            //从heap中释放FA
               free_to_heap (mmb, &__malloc_mmb_heap);

               /* Do the actual munmap.  */
               munmap ((void *)mmb_start, mmb_end - mmb_start);

               __heap_lock (heap);

#  ifdef __UCLIBC_HAS_THREADS__
               
               prev_mmb = 0;
               mmb = __malloc_mmapped_blocks;
#  else
               mmb = next_mmb;
#  endif
             }
           else
             {
               prev_mmb = mmb;
               mmb = mmb->next;
             }

           MALLOC_MMB_DEBUG_INDENT (-1);
         }

      if (start != end)
         /* Hmm, well there's something we couldn't unmap, so put it back
            into the heap.  */
         {
           MALLOC_MMB_DEBUG (0, "putting tail region back into heap: 0x%x[%d]",
                                start, end - start);
           __heap_free (heap, (void *)start, end - start);
         }

      MALLOC_MMB_DEBUG_INDENT (-1);

# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */

      /* MEM/LEN may not be page-aligned, so we have to page-align them,
          and return any left-over bits on the end to the heap.  */
      unmap_start = MALLOC_ROUND_UP_TO_PAGE_SIZE (start);
      unmap_end = MALLOC_ROUND_DOWN_TO_PAGE_SIZE (end);

     
      if (unmap_start > start)
         {
           if (unmap_start - start
             unmap_start += MALLOC_PAGE_SIZE;
           __heap_free (heap, (void *)start, unmap_start - start);
         }
      if (end > unmap_end)
         {
           if (end - unmap_end
             unmap_end -= MALLOC_PAGE_SIZE;
           __heap_free (heap, (void *)unmap_end, end - unmap_end);
         }

           __heap_unlock (heap);

      if (unmap_end > unmap_start)
         /* Finally, actually unmap the memory.  */
         munmap ((void *)unmap_start, unmap_end - unmap_start);

# endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */

#endif /* MALLOC_USE_SBRK */
    }

  MALLOC_DEBUG_INDENT (-1);
}
注意
if (__heap_is_empty (heap))
{
           /* Put the reserved memory back in the heap; we asssume that
              MALLOC_UNMAP_THRESHOLD is greater than MALLOC_MIN_SIZE, so
              we use the latter unconditionally here.  */
           __heap_free (heap, (void *)start, MALLOC_MIN_SIZE);
           start += MALLOC_MIN_SIZE;
}
这里指的是,如果要删除的是堆中的整块内存,造成了堆为空的情况,此时,应该保留heap的最低内存空间,即MALLOC_MIN_SIZE大小
看懂了malloc之后,free应该是很容易的,这里不再详细分析了
七:总结:
         在malloc分配内存的时候,size是按sizeof(double),那也就是说如果申请的不足sizeof(double),malloc还是会分配sizeof(double)。
     内存越界的探讨:如果分配的内存为一个char 而此时,malloc实际上已经分配了一个double大小,在double大小里使用返回的指针,应该是不会造成内存越界的。
         我在写这篇文章的时候,参考了风微柳细(
http://blog.iyi.cn/hily
) 的一篇名为“uClibc 中的 malloc 和 free”的文章,并结合他提供的uclibc代码进行分析,这里先谢谢了。此外,它在文中还提到:
在free内存的时候:
“在检查到空闲链表为空时,为何不把模块初始化时产生的静态空闲域 initial_fa._fa 赋给 heap 中的 free_areas?而偏偏要到将要释放的空间里割出一块呢?”
这是因为静态数组的空间可能已经被使用了。然后全局heap指针上移,要释放的内存的起始位置并不是初始化堆的起始位置了。
举例。最先分得512字节,然后一直没释放,然后,又申请10个page的内存,然后再把10 个page的内存释放掉,此时引起内存回收。全局heap是指向512上面的空间了。
希望你能看到,并能帮助到你 ^_^


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/51562/showart_459148.html

Tags: 网吧 硬件 价格 最新  
责任编辑:Cn029.Com
  • 请文明参与讨论,禁止漫骂攻击。 用户名:新注册) 验证码: 验证码,看不清楚?请点击刷新验证码

    分 值:100分 85分 70分 55分 40分 25分 10分 0分

    评论总数:0条,平均得分:0[ 查看全部 ] 网友评论
    关于我们 - 联系我们 - 广告服务 - 法律声明 - RSS订阅 - 网站地图 - 返回顶部