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高速缓存. 内存管理的目标是提供一种方法,为实 ...
随机推荐
- ML(4): NavieBayes在R中的应用
朴素贝叶斯方法是一种使用先验概率去计算后验概率的方法, 具体见上一节. 算法包:e1071 函数:navieBayes(formule,data,laplace=0,...,subset,na.act ...
- 跟着刚哥梳理java知识点——HelloWorld和常见问题(一)
1.按照国际惯例,写一段输出HelloWorld的java语句: public class HelloWorld { //这是main方法,程序的主入口 public static void main ...
- effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
- python os模块常用方法
OS模块是Python标准库中的一个操作模块,主要用于处理Linux操作系统中的文件和目录 1.要使用OS必须先导入OS import os 2.os.getcwd()获取当前路径. print os ...
- java多线程基本概述(七)——join()方法
在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用join()方法.调用join()方法的意思是当前线程 ...
- Android系统--输入系统(七)Reader_Dispatcher线程启动分析
Android系统--输入系统(七)Reader_Dispatcher线程启动分析 1. Reader/Dispatcher的引入 对于输入系统来说,将会创建两个线程: Reader线程(读取事件) ...
- angular 实现导航ng-click切换
angular写的导航.自学angular已有一段时间. <!doctype html><html lang="en"><head> <m ...
- LinkCode 下一个排列、上一个排列
http://www.lintcode.com/zh-cn/problem/next-permutation-ii/# 原题 给定一个若干整数的排列,给出按正数大小进行字典序从小到大排序后的下一个排列 ...
- spring cloud 集成 swagger2 构建Restful APIS 说明文档
在Pom.xml文件中引用依赖 <dependencies> <dependency> <groupId>org.springframework.cloud< ...
- npm install fetchmatedata慢的解决办法
最近在开发webpack工程时,第一步npm install这里超级慢,一直停着,显示:"fetchMetadata: sill mapToRegistry uri https://regi ...