Uclibc是嵌入式linux系統裡面使用最多的c lib庫。最近在學習linux內核內存管理方面的東西,學完之後一直對用戶空間的內存管理很迷糊,特找了libc中的malloc部份代碼研究了一下,小有心得。特總結成此文。
本文檔結構:
一:准備知識
二:堆空間的管理結構
三:堆空間的初始化
四:FA結構的操作
五:malloc的實現
六:free的實現
七:總結
一: 准備知識:
用戶空間中,經常會調用malloc 與 free進行內存管理,它是在進程的堆空間中分配內存。如下圖所示:
二:堆空間的管理結構:
堆空間表示的數據結構
struct heap
{
//堆空間空閒區的表示結構
struct heap_free_area *free_areas;
//用於在多線程環境中加鎖保護
#ifdef HEAP_USE_LOCKING
pthread_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;
else
heap->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;
else
heap->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)