haproxy内存管理-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的时候,会取到整个内存块。

过程图解

总结

  1. 对二级指针进行*操作,会取到32位地址
  2. buffer的前32位是地址
  3. 同一个地址,都进行*操作,会因类型不同而取到不同值,这就是《CSAPP》说的,信息是位+上下文。
  4. 羡慕指针玩得6的人。
原文地址:https://www.cnblogs.com/shenlinken/p/6919592.html