haproxy的記憶體管理中,通過pool_head free_list,存儲空閑記憶體塊,free_list是個二級指針,卻把空閑記憶體塊都串了起來,沒有用next,pre之類的指針。怎麼實現的?著實思考了半個小時才明白。 pool_head結構: 可知,free_list是個二級指針,二級指針是指向指 ...
haproxy的記憶體管理中,通過pool_head->free_list,存儲空閑記憶體塊,free_list是個二級指針,卻把空閑記憶體塊都串了起來,沒有用next,pre之類的指針。怎麼實現的?著實思考了半個小時才明白。
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]; /* 記憶體池名稱 */
};
可知,free_list是個二級指針,二級指針是指向指針的指針,對二級指針進行*操作,會得到一級指針指向的地址。
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; \
})
當free_list為NULL時,調用pool_refill_alloc申請記憶體,看到這裡的時候有點懵逼,這樣的話,一直申請記憶體,pool->free_list還是一直是NULL,就算不是NULL,pool->free_list = *(void **)pool->free_list又是什麼鬼?
後面看記憶體回收才明瞭。
#define pool_free2(pool, ptr) \
({ \
*(void **)ptr = (void *)pool->free_list; \
pool->free_list = (void *)ptr; \
pool->used--; \
pool_gc2_ifneed(pool); \
})
下麵這句,往*ptr,即申請的記憶體塊(取名為buff0)中寫入pool->free_list的值,pool->free_list是個二級指針,所以記憶體塊的前32位就寫入了一個地址,這個地址可能是NULL,也可能指向下一個記憶體塊。
*(void **)ptr = (void *)pool->free_list;
然後,
pool->free_list = (void *)ptr;
pool->free_list等於了ptr,所以,現在pool->free_list指向了buff0。
所以,在申請記憶體中,
pool->free_list = *(void **)pool->free_list;
對pool->free_list進行*操作,因其是二級指針,所以取到的是第一塊buffer的前32位元組,而前32位元組存的是第二塊buffer的地址,所以free_list變成指向第二塊buffer,嗯,第一塊已經分配出去了,在if的判斷語句里有
if ((__p = pool->free_list) == NULL)
所以此時__p指向了第一塊記憶體。因為p是一級指針,所以在使用*p的時候,會取到整個記憶體塊。
過程圖解
總結
- 對二級指針進行*操作,會取到32位地址
- buffer的前32位是地址
- 同一個地址,都進行*操作,會因類型不同而取到不同值,這就是《CSAPP》說的,信息是位+上下文。
- 羡慕指針玩得6的人。