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;
}
haproxy-代码阅读-内存管理的更多相关文章
- Python内存管理机制-《源码解析》
Python内存管理机制 Python 内存管理分层架构 /* An object allocator for Python. Here is an introduction to the layer ...
- oc内存管理总结(一)
**内存管理 问题 1.什么是ios内存管理? 就是在对象不再被使用的时候,把它即时的从内存中清除掉 2.为什么要使用内存管理? 1.严格的内存管理,能够是我们的应用程在性能上有很大的提高 2.如果忽 ...
- ios内存管理2-对象之间的内存管理
同之前一样,新建一个基于命令行的工程,在新建一个Student类和一个Book类 编写如下代码: Student.h // // Student.h // 内存管理2-对象之间的内存管理 // // ...
- iOS ARC编译器规则和内存管理规则
iOS 开发当中,自动引用计数已经是标准的内存管理方案.除了一些老旧的项目或者库已经没有人使用手动来管理内存了吧. ARC无疑是把开发者从繁琐的保留/释放引用对象逻辑中解脱出来.但这并不是万事大吉了, ...
- 《代码的未来》读书笔记:内存管理与GC那点事儿
一.内存是有限的 近年来,我们的电脑内存都有好几个GB,也许你的电脑是4G,他的电脑是8G,公司服务器内存是32G或者64G.但是,无论内存容量有多大,总归不是无限的.实际上,随着内存容量的增加,软件 ...
- effective OC2.0 52阅读笔记(五 内存管理)
第五章:内存管理 29 理解引用计数 30 以ARC简化引用计数 总结:ARC通过命名约定将内存管理规则标准化.其他编程语言很少像OC这样强调命名.ARC通过设置全局数据结构(此数据结构的具体内容因处 ...
- iOS性能优化之内存管理:Analyze、Leaks、Allocations的使用和案例代码
最近接了个小任务,和公司的iOS小伙伴们分享下instruments的具体使用,于是有了这篇博客...性能优化是一个很大的话题,这里讨论的主要是内存泄露部分. 一. 一些相关概念 很多人应该比较了解这 ...
- Objective-C 内存管理与高级环境编程 阅读分享
常用的调试私有API uintptr_t objc_rootRetainCount(id obj) _objc_autoreleasePoolPrint();//查看自动释放池中的对象 LLVM cl ...
- linux内存管理--slab及其代码解析
Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...
随机推荐
- mysql 免安装版 + sqlyog 安装 步骤 --- 发的有点晚
总有些朋友不会安装mysql,其实软件安装不是学习mysql的重点,基本上也就安装一次,工作后一般公司里也不会让你安装,如果非要安装,百度一下就行了.安装版本百度上有许多,下面就提供一个免安装版的步骤 ...
- 关于 this对象 指向问题
this 定义:this是包含它的函数作为方法被调用时所属的对象.(1,this所在的函数.2,此函数作为方法被调用.3,this等于调用此函数的对象) this 对象在运行时基于函数的执行环境绑定的 ...
- python去除文本中的HTML标签
def SplitHtmlTag(file): with open(file,"r") as f,open("result.txt","w+" ...
- 关于ajax post请求,参数过大产生的问题解决 Java
之前做了一个图片上传的功能,前端是把图片编码成BASE64,但是图片一大了,后台用request.getParameter("前端参数");来接收参数打印不出来,没有值,这就很尴尬 ...
- 什么是NoSQL
NoSQL = Not Only SQL 不仅仅是SQL NoSQL,指的是非关系型的数据库(没有声明性查询语言,没有预定义的模式,可以为键 - 值对存储,列存储,文档存储,图形数据库).不同于传统的 ...
- angular中路由的实现(针对新手)
最近搜了一下网上的教程,看完总感觉有点糊涂,对于新手来说可能云里雾里,所以写一个最简单的路由来给大家做个指引. 首先当然需要准备angular,下载地址:https://angular.io/ 现在a ...
- Linq: Aggregate
Aggregate累加器 今天看东西的时候看见这么个扩展方法Aggregate(累加器)很是陌生,于是乎查了查,随手记录一下. 直接看一个最简答的版本,其他版本基本没什么区别,需要的时候可看一下 pu ...
- NuGet(Nuget Packages)
Nuget是一个.NET平台下的开源的项目,它是Visual Studio的扩展.在使用Visual Studio开发基于.NET Framework的应用时,Nuget能把在项目中添加.移除和更新引 ...
- bzoj3939 【USACO 2015 FEB GOLD 】cow hopscotch
Description 就像人类喜欢玩"跳房子"的游戏,农民约翰的奶牛已经发明了该游戏的一个变种自己玩.由于笨拙的动物体重近一吨打,牛跳房子几乎总是以灾难告终,但这是没有阻止奶牛几 ...
- poj1751最小生成树
The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a very poor system of p ...