博所搬至http://xiaogr.com
全部博文(79)
分类: LINUX
2008-01-07 18:10:23
五:malloc的实现:
分析完FA的操作之后,就可以来分析malloc与free的具体实现了。先分析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个单位