HAproxy 和Agent的内存管理
来源:互联网 发布:鹏鹏扣字软件谁? 编辑:程序博客网 时间:2024/06/06 20:31
今天读了agent的内存管理,其优势在于不用频繁地申请和释放内存,从而消耗时间,但是也有劣势在于内存只会增加,不会下降。那么下面来解读一下它的实现。
一:
首先从基本架构来说,可以看到,在内存里面其实是由链表连接的pool。
每个pool包含了一个链表和size,链表内的每个项表示每个内存块,每个内存块的大小由size决定,。可以看下面的数据结构。一些重要的数据项已经用注释说明。
struct pool_head { void **free_list;//可以理解为链表,free_list的值表示当前可以分配的地址,*free_list的值表示下一块可以分配的地址 CIRCLEQ_ENTRY(pool_head) pool_circqe;// 用来连接pool的数据项 unsigned int used;//表示当前pool内已经使用的内存块 unsigned int allocated;//表示当前pool已经分配的内存块 unsigned int limit; unsigned int minavail;// unsigned int size;//表示每个内存块的大小 unsigned int flags; unsigned int users; char name[12];};
二:
看完了数据结构,那么pool创建的时候是怎么样的呢?
看下述函数,有3个参数,第一个参数表示当前pool的名字,第二个表示pool内存块的大小。
其实思想比较简单,就是遍历当前所有pool,然后找到跟想要分配size相同的内存,如果找到了, 就公用。不然新创建一个,插入队列。
具体细节可以看下面的注释。
struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) { struct pool_head *pool; struct pool_head *entry; struct pool_head *start; unsigned int align; align = 16; size = (size + align - 1) & -align;// 让size为16的倍数 start = NULL; pool = NULL; CIRCLEQ_FOREACH(entry,&pools,pool_circqe)//变量当前分配的pool { if (entry->size == size) { if (flags & entry->flags & MEM_F_SHARED) { //如果size大小相等且都为shared,则直接用这个pool就可以了 pool = entry; log_debug("Sharing %s with %s\n", name, pool->name); break; } } else if (entry->size > size) { log_debug("no suitable pool for %s", name); start = entry; break; } } if (!pool) {//如果没找到 pool = calloc(1, sizeof(*pool));//分配pool的内存 if (!pool) { log_error("allocate %s error,no more memory!", name); return NULL; } if (name) da_strlcpy(pool->name, name, sizeof(pool->name)); pool->size = size;//让pool的size等于入参size pool->flags = flags; if(start==NULL)//判断是不是空队列,如果空队列,插头,否则插start后面 { CIRCLEQ_INSERT_HEAD(&pools, pool, pool_circqe); } else { CIRCLEQ_INSERT_AFTER(&pools, start, pool, pool_circqe); } } pool->users++; return pool;}
三:
那下一步是怎么分配内存,分配内存的代码很简单,如下示例
struct msg *m = pool_alloc(pool2_msg);//pool2_msg 是pool_head类型的
那么这个pool_alloc函数(其实是个宏定义)是怎么实现的呢?
它有两种可能,
1. 当前free_list没有可用的内存了(即(void *)free_list == NULL),那么它就调用pool_refill_alloc这个函数来分配内存,直接返回给上述struct msg类型的m。pool_refill_alloc就不再赘述了,就是calloc一下内存,让pool->used++, pool->allocated++;
2. 当前free_list还有可用内存,那么就将free_list往后移一格,即((pool)->free_list = (void *)(pool)->free_list), 然后返回(void *)free_list;
这里面有些指针比较难,列一下,可以反复思考下,理解下:
(pool)->free_list = (void *)(pool)->free_list;
看到这,我当时蒙了,这样来说free_list岂不是一直为NULL,那么就可以看下面的释放内存了。
#define pool_alloc(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; \})
四
释放内存:
代码比较简单,分为了3步走
1: 让当前(pool)->free_list转为(void ), 然后ptr转为(void *)之后*ptr = (pool)->free_list。
2. (pool)->free_list = (void *)ptr
3. (pool)->used–; 减少pool内存用的数量
这样我们等于ptr的后面挂了free_list的当前可用节点,ptr是当前可用节点内存块。
这里面有些指针比较难,列一下,可以反复思考下,理解下:
(void *) ptr
(void *)(ptr)
其实到这,我们不禁思考,一个calloc必定对应free 的呢?这样岂不是内存泄漏了?
No: 后面还有一个memory gc的操作,这个操作会真正释放内存,这个操作可以作为在程序退出的时候执行,或者接收信号量异步释放
#define pool_free(pool, ptr) \({ \ if (likely((ptr) != NULL)) { \ *(void **)(ptr) = (void *)(pool)->free_list; \ (pool)->free_list = (void *)(ptr); \ (pool)->used--; \ } \})
五:
真正的内存释放:
很简单了,看注释吧
CIRCLEQ_FOREACH(entry,&pools,pool_circqe)//遍历所有pool { void *temp, *next; next = entry->free_list;//pool中free_list的元素 while (next && entry->allocated > entry->minavail && entry->allocated > entry->used) { //变量freelist元素 temp = next; next = *(void **) temp;// next指向free_list下一个元素,temp用来被释放 entry->allocated--; free(temp);//释放真正的内存 } entry->free_list = next;//注意这句话哦,要赋值哦,不然思考下后果? }
完:
这个内存管理还是比较有意思的, 自己在写之前也不是特别清晰,写完自己也清楚了很多,这是一个内存管理方案,下次把Nginx的内存管理方案再摸清楚一点,写清楚点。
- HAproxy 和Agent的内存管理
- Haproxy代码分析系列:内存管理
- Haproxy的详解和配置
- OpenSSH 密钥管理:ssh-agent和keychain
- 内存的问题和管理
- 内存管理的概念和内存分区...
- 内存管理的概念和内存分区
- Swift里的内存管理:内存管理、weak和unowned
- LVS 和 Nginx 和 HAproxy 的区别
- HAProxy内存池简介
- haproxy的安装和基本设置
- keepalied和haproxy的部署及配置
- JVM的内存管理和垃圾回收
- windows和linux的内存管理
- 内存的分配管理和释放
- TL2内存申请和释放的管理
- windows和linux的内存管理
- iOS的多核编程和内存管理
- nginx图片防盗链
- 关于打算android中用子线程开启子线程的问题笔记
- Retrofit源码解析:RxJavaCallAdapterFactory
- Spring security集成CAS
- android应用相关目录的存取方式与函数解析
- HAproxy 和Agent的内存管理
- 那些走在身后的时间
- 强大的SpannableStringBuilder,玩转文本特效
- spark基本知识点之Shuffle
- 根据wsdl文件或者wsdl地址生成对应的java代码(借助MyEclipse工具快速生成Axis1的客户端代码)
- R语言各种查询
- Hdfs 的读写操作
- 基于开源jabber(XMPP)架设内部即时通讯服务的解决方案
- 关于Avoid non-default constructors in fragments的错误