Haproxy代码分析系列:内存管理
来源:互联网 发布:起诉淘宝网胜诉案例 编辑:程序博客网 时间:2024/05/17 06:01
Haproxy实现了自己的内存管理,主要思路是为经常使用的数据结构维护一个内存池,把所有的内存池再串起来,申请和释放内存时,首先到该内存池链表中查找该类型的内存池是否有空闲内存,有的话直接使用,没有的话再重新分配。
代码主要在src/Memory.c中,文章来源于:
Haproxy中的内存池结构是:
struct pool_head {void **free_list;struct list list; /* list of all known pools */unsigned int used; /* how many chunks are currently in use */unsigned int allocated; /* how many chunks have been allocated */unsigned int limit; /* hard limit on the number of chunks */unsigned int minavail; /* how many chunks are expected to be used */unsigned int size; /* chunk size */unsigned int flags; /* MEM_F_* */unsigned int users; /* number of pools sharing this zone */char name[12]; /* name of the pool */};
used,allocated,limit,minavail,size,users,是某个具体内存池使用情况的计数器,flags可以设置该内存池是否可以共享使用(MEM_F_SHARED)。
haproxy的list结构比较简单,是一个双向链表,通过list数据结构达到串起来的目的。
struct list {struct list *n; /* next */struct list *p; /* prev */};
因此haproxy的内存池数据结构如下:
- pool创建
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;/* We need to store at least a (void *) in the chunks. Since we know * that the malloc() function will never return such a small size, * let's round the size up to something slightly bigger, in order to * ease merging of entries. Note that the rounding is a power of two. */align = 16;size = (size + align - 1) & -align;start = &pools;pool = NULL;list_for_each_entry(entry, &pools, list) {if (entry->size == size) {/* either we can share this place and we take it, or * we look for a sharable one or for the next position * before which we will insert a new one. */if (flags & entry->flags & MEM_F_SHARED) {/* we can share this one */pool = entry;DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name);break;}}else if (entry->size > size) {/* insert before this one */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;#ifdef USE_MEM_POOL3LIST_INIT(&pool->free_block_list);#endifLIST_ADDQ(start, &pool->list);}pool->users++;return pool;}
分配一个内存池时,需要指定名称name,大小size和标记flag。
pools是一个全局变量,指向内存池链表的头,遍历内存池链表,如果有块大小相同的并且可以共用的内存池,更新users数目,如果没有可共用的内存池,则新建一个名为name的内存池,设置size,name和users=1。
注意,内存池链表按照size从小到大排列,每次会调整头pools的位置,在适合的位置插入新的pool。
- pool销毁
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,首先free该pool的freelist,通过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;/* here, we should have pool->allocate == pool->used */}
free_list中释放后,如果该pool还有内存在被使用(used != 0),则返回,否则判断该pool是否有其它数据结构共享,如果users为0,则彻底删除该pool
- 内存申请
#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; \})首先从pool的free_list中取得第一个空闲内存块,分配之,注意此处直接把free_list的下一个空闲块的地址写在的上一个空间开头处,相当于实现了next的机制;如果为空,则调用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);if (!ret) {pool_gc2();ret = MALLOC(pool->size);if (!ret)return NULL;}pool->allocated++;pool->used++;return ret;}其中pool_gc2是对pools所有的内存池的free_list进行相应的free,以空出新的内存供MALLOC。
- 内存释放
#define pool_free2(pool, ptr) \({ \ if (likely((ptr) != NULL)) { \ *(void **)ptr = (void *)pool->free_list;\ pool->free_list = (void *)ptr; \ pool->used--; \ } \})
释放时,将该内存放到该pool的空闲列表,注意此处把free_list的地址写到的要free的空间的头部,然后把free_list指向了该内存地址ptr,,并不真正的free,而是把空间保留下来已被后用,这也是haproxy的一个策略。
注:文章对http://blog.chinaunix.net/uid-10249062-id-163274.html做了扩充,多贴了一些代码。
--end
- Haproxy代码分析系列:内存管理
- Haproxy代码分析系列-一些小的Tips
- HAproxy 和Agent的内存管理
- eMule代码分析(2)------内存管理
- HAProxy内存池实现源码分析
- uClinux内存管理分析
- uClinux内存管理分析
- Android内存管理分析
- Android内存管理分析
- Java内存管理分析
- memcached 内存管理 分析
- 内存管理分析
- JAVA内存管理分析
- Cocos2d内存管理分析
- 内存管理分析
- Memcached内存管理分析
- Linux 内存管理分析
- Java内存管理分析
- SQL大全
- HDU 2159 FATE
- HTTP1.0和HTTP1.1的区别
- linux下文件和目录颜色代表的意思
- github快速使用指南
- Haproxy代码分析系列:内存管理
- 神奇的c++等号重载
- 阿里巴巴2011年校招试题
- 2012黑客工具包.zip
- 广东一伙劫匪在抢劫银行时说了一句至理名言!!震惊了许多人
- ExtJS Store 方法以及属性介绍
- Automatic Reference Counting
- tellg用法
- 第九天 T—SQL小结续以及数据库的一些其他