Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2759928
  • 博文数量: 79
  • 博客积分: 30130
  • 博客等级: 大将
  • 技术积分: 2608
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-22 14:58
个人简介

博所搬至http://xiaogr.com

文章存档

2015年(2)

2009年(3)

2008年(56)

2007年(18)

分类: LINUX

2008-01-07 18:10:23

五:malloc的实现:

分析完FA的操作之后,就可以来分析mallocfree的具体实现了。先分析malloc

在分析malloc之前,有必要分析一下几个问题:

1:从上面__heap_free_area_alloc函数的分析可以看到。分配内存时,只是调整了空闲区的大小或者是分配了整个空闲区。那释放内存的时候,怎么才能知道要释放多少呢。(free()中并没有指大小参数)?

2:如果堆的空间不够了,该怎么办?如何廷伸?

关于1:用malloc分配内存的时候,它经常要多分配一点,因为在所分得内存前面要保留一小段来存储所分配的大小。这样在释放内存的时候,就能找到要释放的大小了。如图所示:

 

MALLOC_SIZE (mem):用来返回所分得的起始地址为mem的内存块大小

MALLOC_BASE (mem):用来计算所分配的起始地址为mem的内存块所对应的实际地址

其实MALLOC_SIZE (mem)是将地址mem退后MALLOC_HEADER_SIZE单位,然后再取值,就能得到大小了。

对于二:可以调用brk()或者mmap来扩展数据段。关于这部份,以后我再给出专题分析。

终于可以到具体的代码实现了:

 

malloc (size_t size)

{

     //略过调试代码

#ifdef MALLOC_DEBUGGING

  static int debugging_initialized = 0;

  if (! debugging_initialized)

    {

      debugging_initialized = 1;

      __malloc_debug_init ();

    }

  if (__malloc_check)

    __heap_check (&__malloc_heap, "malloc");

#endif

 

     //参数有效性检测。这里没有检测参数为负的情况

  if (size == 0)

    return 0;

 

  return malloc_from_heap (size, &__malloc_heap);

}

函数转入malloc_from_heap (size, &__malloc_heap)

它的实现如下:

//传入参数:

//size:想要分配的内存大小。heap:即为__malloc_heap

static void *

malloc_from_heap (size_t size, struct heap *heap)

{

  void *mem;

  MALLOC_DEBUG (1, "malloc: %d bytes", size);

  /* Include extra space to record the size of the allocated block.  */

//实际要分配的大小,见前面的分析

  size += MALLOC_HEADER_SIZE;

//为防止竞态,加锁

  __heap_lock (heap);

 

  /* First try to get memory that's already in our heap.  */

//首先尝试从heap分配内存.这函数见前面的分析

  mem = __heap_alloc (heap, &size);

     //解锁

  __heap_unlock (heap);

 

  if (unlikely (! mem))

     {

     //如果分配失败,那就说明空闲区不足,向内核申请

      void *block;

     //计算要向内核申请的大小,至少要为一个page,即4096

      size_t block_size

     = (size < MALLOC_HEAP_EXTEND_SIZE

        ? MALLOC_HEAP_EXTEND_SIZE

        : MALLOC_ROUND_UP_TO_PAGE_SIZE (size));

 

      /* Allocate the new heap block.  */

//两种方式,一种是sbrk() 另一种是mmap()。后面做为一个专题介绍

#ifdef MALLOC_USE_SBRK

 

      __malloc_lock_sbrk ();

 

      /* Use sbrk we can, as it's faster than mmap, and guarantees

      contiguous allocation.  */

      block = sbrk (block_size);

      if (likely (block != (void *)-1))

     {

       /* Because sbrk can return results of arbitrary

          alignment, align the result to a MALLOC_ALIGNMENT boundary.  */

       long aligned_block = MALLOC_ROUND_UP ((long)block, MALLOC_ALIGNMENT);

       if (block != (void *)aligned_block)

         /* Have to adjust.  We should only have to actually do this

            the first time (after which we will have aligned the brk

            correctly).  */

         {

           /* Move the brk to reflect the alignment; our next allocation

          should start on exactly the right alignment.  */

           sbrk (aligned_block - (long)block);

           block = (void *)aligned_block;

         }

     }

 

      __malloc_unlock_sbrk ();

 

#else /* !MALLOC_USE_SBRK */

 

      /* Otherwise, use mmap.  */

      block = mmap (0, block_size, PROT_READ | PROT_WRITE,

              MAP_SHARED | MAP_ANONYMOUS, 0, 0);

 

#endif /* MALLOC_USE_SBRK */

 

      if (likely (block != (void *)-1))

     {

#if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)

       struct malloc_mmb *mmb, *prev_mmb, *new_mmb;

#endif

 

       MALLOC_DEBUG (1, "adding system memroy to heap: 0x%lx - 0x%lx (%d bytes)",

              (long)block, (long)block + block_size, block_size);

 

       /* Get back the heap lock.  */

       __heap_lock (heap);

 

       /* Put BLOCK into the heap.  */

         //将申请的内存加入heap

       __heap_free (heap, block, block_size);

 

       MALLOC_DEBUG_INDENT (-1);

 

       /* Try again to allocate.  */

     //重新向heap申请内核,因为此时已经有足够的空闲内存了

       mem = __heap_alloc (heap, &size);

 

       __heap_unlock (heap);

 

#if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)

       /* Insert a record of BLOCK in sorted order into the

          __malloc_mmapped_blocks list.  */

 

       for (prev_mmb = 0, mmb = __malloc_mmapped_blocks;

            mmb;

            prev_mmb = mmb, mmb = mmb->next)

         if (block < mmb->mem)

           break;

 

       new_mmb = malloc_from_heap (sizeof *new_mmb, &__malloc_mmb_heap);

       new_mmb->next = mmb;

       new_mmb->mem = block;

       new_mmb->size = block_size;

 

       if (prev_mmb)

         prev_mmb->next = new_mmb;

       else

         __malloc_mmapped_blocks = new_mmb;

 

       MALLOC_MMB_DEBUG (0, "new mmb at 0x%x: 0x%x[%d]",

                  (unsigned)new_mmb,

                  (unsigned)new_mmb->mem, block_size);

#endif /* !MALLOC_USE_SBRK && __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */

     }

    }

 

  if (likely (mem))

    /* Record the size of the block and get the user address.  */

    {

         //已经分得了内存,调整分得的内存,留出写大小的空间,调整要返回给程序的地址

      mem = MALLOC_SETUP (mem, size);

 

      MALLOC_DEBUG (-1, "malloc: returning 0x%lx (base:0x%lx, total_size:%ld)",

             (long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));

    }

  else

    MALLOC_DEBUG (-1, "malloc: returning 0");

 

  return mem;

}

跟踪一下MALLOC_SETUP (mem, size):

#define MALLOC_SETUP(base, size)  \

  (MALLOC_SET_SIZE (base, size), (void *)((char *)base + MALLOC_HEADER_SIZE))

#define MALLOC_SET_SIZE(base, size)  (*(size_t *)(base) = (size))

MALLOC_SET_SIZE,将大小写入内存开始的前一部份。

Base+ MALLOC_HEADER_SIZE:地址上移MALLOC_HEADER_SIZE个单位

阅读(3320) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~