Uclibc中的malloc机制分析

  • 格式:pdf
  • 大小:466.89 KB
  • 文档页数:18

Uclibc中的malloc机制分析Uclibc是嵌入式linux系统里面使用最多的c lib库。

最近在学习linux内核内存管理方面的东西,学完之后一直对用户空间的内存管理很迷糊,特找了libc中的malloc部份代码研究了一下,小有心得。

特总结成此文。

本文档结构:一:准备知识二:堆空间的管理结构三:堆空间的初始化四:FA结构的操作五:malloc的实现六:free的实现七:总结一: 准备知识:用户空间中,经常会调用malloc 与 free进行内存管理,它是在进程的堆空间中分配内存。

如下图所示:二:堆空间的管理结构:堆空间表示的数据结构struct heap{//堆空间空闲区的表示结构struct heap_free_area *free_areas;//用于在多线程环境中加锁保护#ifdef HEAP_USE_LOCKINGpthread_mutex_t lock;#endif};heap_free_area结构在代码被代码作者称之为FA结构。

它的定义如下:struct heap_free_area{//空闲区的大小size_t size;//用于构造循环链表struct heap_free_area *next, *prev;};注意:在FA结构里并没有定义指向空闲区的指针,这是因为FA结构正好放在空闲区的后面。

堆栈区空间结构如下所示:三:堆空间的初始化:全局变量__malloc_heap表示了整个堆栈空间。

它的初始化过程如下示:struct heap __malloc_heap = HEAP_INIT_WITH_FA (initial_fa);HEAP_INIT_WITH_FA的定义如下:#ifdef HEAP_USE_LOCKING# define HEAP_INIT { 0, PTHREAD_MUTEX_INITIALIZER }# define HEAP_INIT_WITH_FA(fa) { &fa._fa, PTHREAD_MUTEX_INITIALIZER }#else# define HEAP_INIT { 0 }# define HEAP_INIT_WITH_FA(fa) { &fa._fa }#endif变量initial_fa初始化如下:HEAP_DECLARE_STATIC_FREE_AREA (initial_fa, 256);#define HEAP_DECLARE_STATIC_FREE_AREA(name, size) \static struct \{ \char space[(size) - sizeof (struct heap_free_area)]; \struct heap_free_area _fa; \} name = { "", { (size), 0, 0 } }如此可以看出初始化的堆空间为256个字节。

从上面的初始化也可以看到,在FA结构的前面静态定义了一个数组空间。

这也印证了上面说的“FA结构正好放在空闲区的后面”四:FA结构的操作:1:#define HEAP_FREE_AREA_SIZE(fa) ((fa)->size)FA所代表的空闲区大小,此大小已经包含FA本身占的空间2:#define HEAP_FREE_AREA_START(fa) ((void *)((char *)(fa + 1) - (fa)->size))FA所代表空闲区的起始位置。

fa+1到达空闲区末端。

指针再下移大小个单位,即为空闲区的起始位置3:#define HEAP_FREE_AREA_END(fa) ((void *)(fa + 1))返回FA所表示空闲区的末尾。

从FA所表示的结构可看出。

从FA的地址上移一个FA的大小,刚好到达空闲的末尾4:#define HEAP_MIN_FREE_AREA_SIZE \HEAP_ADJUST_SIZE (sizeof (struct heap_free_area) + 32)最少的空闲区大小。

空闲区最少要能存上一个heap_free_area大小,此外还要有32字节的空闲,这是从效率来考虑的。

Malloc分配内存的时候,有时候它会把一个FA分为两段。

如果剩余的内存少于HEAP_MIN_FREE_AREA_SIZE.还不如全部都将内存分配出去。

因为维护空闲内存需要影响效率。

这从我们后面的malloc 与 free分析中可以看到5:__heap_delete (struct heap *heap, struct heap_free_area *fa)该函数是将fa从heap中删除,它的实现如下:extern inline void__heap_delete (struct heap *heap, struct heap_free_area *fa){if (fa->next)fa->next->prev = fa->prev;if (fa->prev)fa->prev->next = fa->next;elseheap->free_areas = fa->next; //如果删除的是它的首节点}只是一个简单的链表操作,将fa从循环链表中脱节。

6:__heap_link_free_area (struct heap *heap, struct heap_free_area *fa,struct heap_free_area *prev,struct heap_free_area *next)从代码注释上看该函数是指prev 与 next 之间的Fa合并到一起。

实际上它只是在prev 与next 之间插入了一项而已。

实现如下:extern inline void__heap_link_free_area (struct heap *heap, struct heap_free_area *fa,struct heap_free_area *prev,struct heap_free_area *next){fa->next = next;fa->prev = prev;if (prev)prev->next = fa;elseheap->free_areas = fa; //插入节点为首节点的情况if (next)next->prev = fa;}7:__heap_link_free_area_after (struct heap *heap,struct heap_free_area *fa,struct heap_free_area *prev)该函数实际上只是fa链接至prev后。

等调用的时候再分析它。

__heap_link_free_area_after (struct heap *heap,struct heap_free_area *fa,struct heap_free_area *prev){if (prev)prev->next = fa;elseheap->free_areas = fa;fa->prev = prev;}8:__heap_add_free_area (struct heap *heap, void *mem, size_t size,struct heap_free_area *prev,struct heap_free_area *next)该函数将从mem地址开始的size大小的内存所代码的FA结构,插入prev和next之间。

它的实现如下:extern inline struct heap_free_area *__heap_add_free_area (struct heap *heap, void *mem, size_t size,struct heap_free_area *prev,struct heap_free_area *next){//先取得内存段所在的FA结构,再将FA结构插入到prev与next之间struct heap_free_area *fa = (struct heap_free_area *)((char *)mem + size - sizeof (struct heap_free_area));fa->size = size;//将fa插入prev.next之间__heap_link_free_area (heap, fa, prev, next);return fa;}这函数的实现很有意思。

它先取内存段的末地址,然后再返回heap_free_area个单位,存上一个FA 结构。

这里也印证了,FA结构刚好放在了空闲区的末尾9:__heap_free_area_alloc (struct heap *heap,struct heap_free_area *fa, size_t size)该函数从fa所表示的空闲中,分配size大小的内存实现如下:extern inline size_t__heap_free_area_alloc (struct heap *heap,struct heap_free_area *fa, size_t size){size_t fa_size = fa->size;//如果该空闲区剩余的内存太少。

将它全部都分配出去//参考HEAP_MIN_FREE_AREA_SIZE的分析if (fa_size < size + HEAP_MIN_FREE_AREA_SIZE)/* There's not enough room left over in FA after allocating the block, sojust use the whole thing, removing it from the list of free areas. */{//将fa从heap中删除__heap_delete (heap, fa);/* Remember that we've alloced the whole area. */size = fa_size;}else/* Reduce size of FA to account for this allocation. */fa->size = fa_size - size;return size;}从上面可以看出,分配内存时,只是简单的缩少了空闲区的长度。

10: __heap_alloc (heap, &size);从堆heap中分配size字节的内存实现如下:void *__heap_alloc (struct heap *heap, size_t *size){struct heap_free_area *fa;size_t _size = *size;void *mem = 0;//根据HEAP_GRANULARITY 对齐 sizeof(double)_size = HEAP_ADJUST_SIZE (_size);//如果要分配的内存比FA结构还要小,那就调整它为FA大小if (_size < sizeof (struct heap_free_area))/* Because we sometimes must use a freed block to hold a free-area node,we must make sure that every allocated block can hold one. */_size = HEAP_ADJUST_SIZE (sizeof (struct heap_free_area));HEAP_DEBUG (heap, "before __heap_alloc");/* Look for a free area that can contain _SIZE bytes. *///遍历堆中的FA,找出有合适大小的空闲区for (fa = heap->free_areas; fa; fa = fa->next)if (fa->size >= _size){/* Found one! */mem = HEAP_FREE_AREA_START (fa);//从该空间中分得内存。