haproxy記憶體池概述 記憶體池按照類型分類,每個類型的記憶體池都有一個名字,用鏈表記錄空閑的記憶體塊,每個記憶體塊大小相等,並按照16位元組對齊。 haporxy用pool_head 結構記錄記憶體池 在程式執行過程中,產生的記憶體池,很有可能按照大小,排列成如下方式: 記憶體池的創建 haproxy創建記憶體池 ...
haproxy記憶體池概述
記憶體池按照類型分類,每個類型的記憶體池都有一個名字,用鏈表記錄空閑的記憶體塊,每個記憶體塊大小相等,並按照16位元組對齊。
haporxy用pool_head 結構記錄記憶體池
struct pool_head {
void **free_list; /* 空閑鏈表 */
struct list list; /* 雙向鏈表,鏈接每種類型的記憶體池 */
unsigned int used; /* 使用了多少記憶體塊 */
unsigned int allocated; /* 分配了多少記憶體塊 */
unsigned int limit; /* 記憶體塊上限 */
unsigned int minavail; /* 最少保留幾個,回收時不會全部回收 */
unsigned int size; /* 記憶體塊大小 */
unsigned int flags; /* 能否共用,類型不同,但大小相同的,能否共用一個pool_head */
unsigned int users; /* 記憶體池有幾個使用者 */
char name[12]; /* 記憶體池名稱 */
};
在程式執行過程中,產生的記憶體池,很有可能按照大小,排列成如下方式:
記憶體池的創建
haproxy創建記憶體池時,會先檢查記憶體池中,有沒有與所需大小相同的記憶體池,有且記憶體池可共用,將pool_head.users++。若沒有,則新創建一個記憶體池。
struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
{
struct pool_head *pool;
struct pool_head *entry;
struct list *start;
unsigned int align;
//按照16位元組對齊
align = 16;
size = (size + align - 1) & -align;
//pools是全局變數,記憶體池的頭節點
start = &pools;
pool = NULL;
list_for_each_entry(entry, &pools, list) {
if (entry->size == size) {
if (flags & entry->flags & MEM_F_SHARED) {//大小相等且可共用
pool = entry;
break;
}
}
else if (entry->size > size) { //記憶體池按照大小排序,新pool_head,插在適當位置
start = &entry->list;
break;
}
}
//創建一個新的記憶體池
if (!pool) {
pool = CALLOC(1, sizeof(*pool));
if (!pool)
return NULL;
if (name)
strlcpy2(pool->name, name, sizeof(pool->name));
pool->size = size;
pool->flags = flags;
LIST_ADDQ(start, &pool->list);
}
pool->users++;
return pool;
}
記憶體申請
create_pool僅僅是申請了記憶體池的類型,還沒有具體分配記憶體,分配記憶體的工作由pool_refill_alloc來完成
void *pool_refill_alloc(struct pool_head *pool)
{
void *ret;
//如果可申請的記憶體塊有上限,且已達上限,不再申請
if (pool->limit && (pool->allocated >= pool->limit))
return NULL;
ret = MALLOC(pool->size);
//如果申請失敗,pool_gc2()垃圾回收,然後再申請一次,再失敗就放棄
if (!ret) {
pool_gc2();
ret = MALLOC(pool->size);
if (!ret)
return NULL;
}
pool->allocated++;
pool->used++;
return ret;
}
其中,pool_gc2()垃圾回收函數,會遍歷所有記憶體池,並釋放空閑記憶體塊(留下minavail的數量)。
使用者申請記憶體,不是直接調用pool_refill_alloc,而是通過調用pool_alloc2,如果free_list中沒有空閑記憶體了,則調用pool_refill_alloc申請下記憶體。如果還有空閑記憶體,則使用第一塊記憶體,free_list指向下一塊。
#define pool_alloc2(pool) \
({ \
void *__p; \
if ((__p = pool->free_list) == NULL) \
__p = pool_refill_alloc(pool); \
else { \
pool->free_list = *(void **)pool->free_list; \
pool->used++; \
} \
__p; \
})
記憶體釋放
如果記憶體塊的使用者,在申請記憶體塊後,不主動釋放記憶體塊,那麼銷毀記憶體池後,記憶體塊將無法回到記憶體。所以,必須註意,要主動釋放記憶體塊。
記憶體塊的釋放很簡單,將記憶體塊直接放到空閑鏈表的第一個節點就行。
#define pool_free2(pool, ptr) \
({ \
*(void **)ptr = (void *)pool->free_list; \
pool->free_list = (void *)ptr; \
pool->used--; \
pool_gc2_ifneed(pool); \
})
銷毀記憶體池
記憶體池的銷毀很簡單,釋放所有空閑記憶體塊,然後釋放記憶體池。如果還有使用中的記憶體(pool->used != 0),停止釋放
void *pool_destroy2(struct pool_head *pool)
{
if (pool) {
pool_flush2(pool);
if (pool->used)
return pool;
pool->users--;
if (!pool->users) {
LIST_DEL(&pool->list);
FREE(pool);
}
}
return NULL;
}
其中, pool_flush2函數會直接釋放掉所有空閑記憶體
void pool_flush2(struct pool_head *pool)
{
void *temp, *next;
if (!pool)
return;
next = pool->free_list;
while (next) {
temp = next;
next = *(void **)temp;
pool->allocated--;
FREE(temp);
}
pool->free_list = next;
}