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高速缓存. 内存管理的目标是提供一种方法,为实 ...
随机推荐
- Python os与sys模块解析
os与sys模块的官方解释如下: os: This module provides a portable way of using operating system dependent functio ...
- 借助case,实现更丰富的分组查询统计
根据fileD6的前4位分组 分别统计该组 5种企业类型fileD31的数量 create or replace view jyjc_bycity as select substr(fileD ...
- 复选框选中删除行(DOM练习)
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- CSS浮动专题!
在css中,浮动问题可能是很多刚入门的小白比较头疼的问题. 1,首先先来介绍一下两种浮动类型:左浮动和右浮动 1) float:left;左浮动,后面的内容会流向对象的右侧 2) float:righ ...
- Android性能优化——之防止内存泄露
又是好久没有写博客了,一直都比较忙,最近终于有时间沉淀和整理一下最近学到和解决的一些问题. 最近进行技术支持的时候,遇到了几个崩溃的问题,都是OOM异常,一般OOM异常给人的感觉应该是加载大图片造成的 ...
- ajax的介绍
$.ajax({ 11 url: "article.asmx/GetArticleByID", 12 type: "POST", 13 datatype: &q ...
- 在spring boot环境中使用fastjson + redis的高速缓存技术
因为项目需求,需要在spring boot环境中使用redis作数据缓存.之前的解决方案是参考的http://wiselyman.iteye.com/blog/2184884,具体使用的是Jackso ...
- .bind.apply() 解决 new 操作符不能用与 apply 或 call 同时使用
背景: 小明想要用数组的形式为 Cls.func 传入多个参数,他想到了以下的写法: var a = new Cls.func.apply(null, [1, 2, 3]); 然而浏览器却报错Cls. ...
- web开发中,post与get的区别
区别: 1.Get是从服务器上获取数据,Post是向服务器传送数据. 2.Get是把参数数据队列加到提交表单的Action属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.Post是 ...
- 关于cisco ccp 或sdm管理gns3中思科路由器的成功分享
本来工作环境中有一台c1841,闲来无事,升级了最新的IOS=c1841-adventerprisek9-mz.151-4.M6.bin,在xp虚拟机中安装sdm(新windows系统不支持)和在wi ...