当前位置: 首页 > article >正文

Nginx内存池源码剖析

能看出来Nginx小块内存和大块内存分界线就是一个页面4k(x86)

#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)//能分配的最大内存#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)//默认池的大小 16k#define NGX_POOL_ALIGNMENT       16//字节对齐
#define NGX_MIN_POOL_SIZE                     //最小的大小                                 \ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \NGX_POOL_ALIGNMENT)

进到ngx_align看到其实就是调整倍数,和SGI STL的做法是一样的

他的数据成员和函数

typedef void (*ngx_pool_cleanup_pt)(void *data);typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;struct ngx_pool_cleanup_s {ngx_pool_cleanup_pt   handler;void                 *data;ngx_pool_cleanup_t   *next;
};typedef struct ngx_pool_large_s  ngx_pool_large_t;struct ngx_pool_large_s {ngx_pool_large_t     *next;void                 *alloc;
};typedef struct {u_char               *last;u_char               *end;ngx_pool_t           *next;ngx_uint_t            failed;//记录分配失败的次数<4后面写死了
} ngx_pool_data_t;struct ngx_pool_s {ngx_pool_data_t       d;size_t                max;ngx_pool_t           *current;ngx_chain_t          *chain;ngx_pool_large_t     *large;ngx_pool_cleanup_t   *cleanup;ngx_log_t            *log;
};typedef struct {ngx_fd_t              fd;u_char               *name;ngx_log_t            *log;
} ngx_pool_cleanup_file_t;ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);//创建内存池
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);void *ngx_palloc(ngx_pool_t *pool, size_t size);//分配内存
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);

创建内存池Create

ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
{ngx_pool_t  *p;p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);//根据用户指定size大小内存对齐,不同平台if (p == NULL) {return NULL;}//初始化p->d.last = (u_char *) p + sizeof(ngx_pool_t);//指向除ngx_pool_t结构的头信息之后的位置p->d.end = (u_char *) p + size;//指向内存池的末尾p->d.next = NULL;p->d.failed = 0;size = size - sizeof(ngx_pool_t);//内存池能使用的大小,size-头部信息p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;//4095	开辟比一个页面小就用size,比一个页面大就用一个页面				p->current = p;//指向内存起始地址p->chain = NULL;p->large = NULL;p->cleanup = NULL;p->log = log;//日志return p;
}

分配内存

当分配小块内存的时候,如果剩的还够分配 

static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{u_char      *m;ngx_pool_t  *p;p = pool->current;do {m = p->d.last;//可分配内存的地址if (align) {m = ngx_align_ptr(m, NGX_ALIGNMENT);//根据平台 调整倍数}if ((size_t) (p->d.end - m) >= size) {//剩余的大于要申请的sizep->d.last = m + size;//把m指针偏移个size字节return m;}p = p->d.next;} while (p);return ngx_palloc_block(pool, size);
}

当剩的不够分配了进入 return ngx_palloc_block(pool, size);

我们看看ngx_palloc_block

第二块内存块之后的里面头信息就不用存max,large那些了,只存用于分配内存的last next那些指针

static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
{u_char      *m;size_t       psize;ngx_pool_t  *p, *new;psize = (size_t) (pool->d.end - (u_char *) pool);//计算要再分配的内存块大小//又开辟一块空间m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);if (m == NULL) {return NULL;}//指向新内存块new = (ngx_pool_t *) m;new->d.end = m + psize;new->d.next = NULL;new->d.failed = 0;m += sizeof(ngx_pool_data_t);//头只存ngx_pool_data_t的成员m = ngx_align_ptr(m, NGX_ALIGNMENT);new->d.last = m + size;//分配出去,指向剩的内存起始地址for (p = pool->current; p->d.next; p = p->d.next) {if (p->d.failed++ > 4) {//当前块内存一直不够分配pool->current = p->d.next; //去下一个内存块}}p->d.next = new;//新生成的内存块接到原来的内存块后面return m;
}

下面看看要是分配大块内存>4k,nginx怎么分配的

整理逻辑就是先malloc把内存分配出来,然后遍历large链表找大块内存的头信息,看看哪个里面是空的被free了,如果找到了就把新分配的内存地址填进去就行,但是遍历了三个还没找到,那就不找了直接退出,利用小块内存分配移动last指针把大小内存头信息分配出来,然后把刚刚分配大块内存填进去就行。nginx处处体现了效率,就看三下,没有就用小块,因为小块的效率高,直接移动指针就行

static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{void              *p;ngx_uint_t         n;ngx_pool_large_t  *large;p = ngx_alloc(size, pool->log);//调mallocif (p == NULL) {return NULL;}n = 0;//遍历链表for (large = pool->large; large; large = large->next) {if (large->alloc == NULL) {large->alloc = p;return p;}if (n++ > 3) {break;}}large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);//通过小块内存把large头分配进去if (large == NULL) {ngx_free(p);return NULL;}large->alloc = p;//大块内存起始地址large->next = pool->large;//头插 连接起来pool->large = large;return p;
}

Nginx对于大块内存提供了free函数

ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p)//释放大块内存,小块不释放
{ngx_pool_large_t  *l;for (l = pool->large; l; l = l->next) {if (p == l->alloc) {ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,"free: %p", l->alloc);ngx_free(l->alloc);l->alloc = NULL;return NGX_OK;}}return NGX_DECLINED;
}

对于小块内存没有提供释放函数

所以小块内存的释放只能用reset重置整个内存池,nginx源码重置里面对于小块内存的处理有点浪费,他全部按照第一块内存那样处理了,但是第二块往后小块内存的头部信息都没有ngx_pool_s这个结构里的成员了,所以更好的应该分别处理

void
ngx_reset_pool(ngx_pool_t *pool)//内存池重置
{ngx_pool_t        *p;ngx_pool_large_t  *l;for (l = pool->large; l; l = l->next) {//大块if (l->alloc) {ngx_free(l->alloc);}}/* for (p = pool; p; p = p->d.next) {//小块p->d.last = (u_char *) p + sizeof(ngx_pool_t);p->d.failed = 0;}*/  这块nginx源码自己写的//下面我改的处理小块内存//处理第一个内存块p=pool;p->d.last = (u_char *) p + sizeof(ngx_pool_t);p->d.failed = 0;//处理第二个开始到剩下的for (p = p->d.next; p; p = p->d.next) {//小块p->d.last = (u_char *) p + sizeof(ngx_pool_data_t);p->d.failed = 0;}pool->current = pool;pool->chain = NULL;pool->large = NULL;
}

对于内存池外部资源的释放

在小块内存内存池创建个clean头信息,开辟完之后把这一块内存起始地址返回回来

void
ngx_destroy_pool(ngx_pool_t *pool)
{ngx_pool_t          *p, *n;ngx_pool_large_t    *l;ngx_pool_cleanup_t  *c;for (c = pool->cleanup; c; c = c->next) {if (c->handler) {ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,"run cleanup: %p", c);c->handler(c->data);}}ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{ngx_pool_cleanup_t  *c;c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));//头信息,小块内存开辟if (c == NULL) {return NULL;}if (size) {c->data = ngx_palloc(p, size);if (c->data == NULL) {return NULL;}} else {c->data = NULL;}c->handler = NULL;c->next = p->cleanup;p->cleanup = c;ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);return c;
}

整个释放流程,先释放外部资源,调用外部资源清楚函数回调,再释放大块,最后小块。因为小块里面会有前面的头信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dgrt.cn/a/392203.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章:

Nginx内存池源码剖析

能看出来Nginx小块内存和大块内存分界线就是一个页面4k&#xff08;x86&#xff09; #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)//能分配的最大内存#define NGX_DEFAULT_POOL_SIZE (16 * 1024)//默认池的大小 16k#define NGX_POOL_ALIGNMENT 16//字节对齐…...

【C++、数据结构】封装map和set(用红黑树实现)

文章目录&#x1f4d6; 前言1. 如何复用同一棵红黑树⚡1.1 &#x1f300; 修改后结点的定义&#xff1a;2. 模拟实现中何实现数据比较大小&#x1f31f;3. 红黑树迭代器的实现&#x1f525;3.1 &#x1f4a5;红黑树begin&#xff08;&#xff09;和 end&#xff08;&#xff09…...

Python-项目实战--飞机大战-pygame快速入门(3)

4.理解精灵和精灵组4.1精灵和精灵组在刚刚完成的案例中&#xff0c;图像加载、位置变化、绘制图像都需要程序员编写代码分别处理为了简化开发步骤&#xff0c;pygame提供了两个类pygame.sprite.Sprite --存储图像数据 image和位置rect的对象pygame.sprite.Group注意&#xff1a…...

【2007NOIP普及组】T4.Hanoi双塔问题 试题解析

【2007NOIP普及组】T4.Hanoi双塔问题 试题解析 时间限制: 1000 ms 内存限制: 65536 KB 【题目描述】 给定A,B,C三根足够长的细柱,在A柱上放有2n个中间有空的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。现要…...

Camtasia2023免费屏幕录像软件支持MP4/AVI/WMV等多种格式

微课教学现在越来越受欢迎&#xff0c;如果你是一名教师&#xff0c;肯定知道喀秋莎的存在&#xff0c;可能曾经在哪儿相遇过&#xff0c;现在甚至还念念不忘&#xff01;如果真的喜欢&#xff0c;这里可以觅到她的倩影了。camtasia是一款十六进制编辑器的软件&#xff0c;camt…...

MySQL中的事务(隔离性详解)

1.什么是事务事务是指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败(通俗的说一组SQL语句,要么全部执行成功,一条语句出错则全部出粗);在不同的环境中,都可以有事务,对应在数据库中,就是数据库事务.2.为什么使用事务事务的核心逻辑就是多条SQL语句要么全…...

iPhone苹果手机Apple id帐号如何永久性注销删除数据?

原文来源&#xff1a;https://www.caochai.com/article-4120.html 注本方法&#xff1a;将会将您的iPhone苹果手机Apple id帐号从所有 Apple App、服务和 iCloud&#xff08;由云上贵州运营&#xff09; 中永久删除你的帐户和相关联的数据。 iPhone苹果手机Apple id帐号如何永…...

CSDN第26期周赛赛后总结(第一次AK)

文章目录前言一、 等差数列1、题目描述2、思路分析3、代码详解二、阿波罗的魔力宝石1、题目描述2、思路分析3、代码详解三、任务分配问题1、题目描述2、思路分析3、代码详解四、单词逆序1、题目描述2、思路分析3、代码详解总结前言 第一次AK&#xff0c;记录与反思一下。 一、 …...

MySQL面试题:MySQL锁机制

文章目录1. 封锁粒度2. 封锁类型读写锁意向锁3. 封锁协议1. 一级封锁协议&#xff08;修改-事务&#xff09;2. 二级封锁协议&#xff08;读取-立即&#xff09;3. 三级封锁协议&#xff08;读取-事务&#xff09;4. 封锁协议与隔离级别5. 两段锁协议a. 概念b. 例子c. 两段锁是…...

带你三分钟了解网络用语之计算机网络概述

计算机网络概述 结点 &#xff08;node&#xff09; &#xff1a;网络中的结点可以是计算机&#xff0c;集线器&#xff0c;交换机或路由器等。主机&#xff08;host&#xff09; &#xff1a;连接在因特网上的计算机。ISP&#xff08;Internet Service Provider&#xff09; …...

基于CNN的人脸识别

前些日子读了一篇关于人脸识别的文章&#xff0c;age and gender classificiation using convolutional neural networks&#xff0c;这是一篇发表在cvpr2015的一篇文章&#xff0c;文章写得很好&#xff0c;条理清晰&#xff0c;逻辑性强&#xff0c;非常适合深度学习者学习&a…...

color transfer between images论文实现

今天闲来无事把经典的颜色迁移文章来拿看看&#xff0c;突然发现自己还没动手实现过color transfer between images这篇文章&#xff0c;想当初自己的毕业设计就是做的这个&#xff0c;真是有点惭愧。 关于这篇文章的代码网上有很多&#xff0c;但是我找了很久&#xff0c;发现…...

C++ CopyFile函数的用法

CopyFile函数定义在Windows.h中&#xff0c;使用时要include之&#xff1b; CopyFile&#xff08;&#xff09;使用如下&#xff1a; #include<Windows.h> int main() {CopyFile("C:\\a.txt","C:\\b.txt",FALSE); }便可将a.txt文件复制到b.txt文件&…...

神经单元

闲来无聊&#xff0c;决定写一下最近的学习笔记&#xff0c;先从最简单的神经单元讲起。 什么是神经单元&#xff1f; 神经单元就是一个计算单元&#xff0c;初学者可以把它理解为一个简单的函数&#xff0c;我从网上截了一张图&#xff1a; 其中x1&#xff0c;x2&#xff0c…...

理解神经网络

这篇博客是接着上一篇神经单元写的&#xff1a;http://blog.csdn.net/zsy162534/article/details/51112337 了解了什么是神经单元&#xff0c;就很容易理解神经网络&#xff0c;神经网络就是一系列神经单元连接而成构成的网络结构&#xff0c;如下图&#xff1a; 这是一个5层神…...

welsh颜色迁移算法实现过程

最近研究了一下color transfer的相关内容&#xff0c;自从实现了Reinhard经典颜色迁移算法后&#xff0c;便思考着能编写代码实现第二个经典算法&#xff1a;welsh算法&#xff0c;本人在编写调试大概一周才终于实现了出来。 welsh算法基本思想&#xff1a; 1.将目标图像和样…...

使用python实现简单全连接神经网络

最近在学习神经网络的相关知识&#xff0c;特在此做一个笔记。 python语言的功能很强大&#xff0c;可以使用很少的代码实现很多功能&#xff0c;因此大家如果想研究深度学习的话&#xff0c;一定要懂得python语言。 这篇笔记记录我的第一次使用python编写神经网络代码的过程…...

使用python进行人脸性别分类

上面一篇文章写到了如何利用python写简单的神经网络代码&#xff0c;并利用全连接神经网络实现简单的mnist手写数字分类&#xff0c;现在我们可以利用此代码做更多的事情。 有一段时间导师让我做人脸识别的问题&#xff0c;最简单的便是人脸性别的分类&#xff0c;当时是在caff…...

C++ sort函数对class类排序

sort是stl中一个经常用到的排序函数&#xff0c;可以对数组或类似数组&#xff08;例如vector&#xff09;的结构进行排序&#xff0c;默认为升序排序。 例如下面的代码对vec进行升序排序&#xff1a; sort(vec.begin(),vec.end());若想降序排序&#xff0c;则只需加greater即可…...

利用Lab空间把春天的场景改为秋天

前一段时间实现了Reinhard颜色迁移算法&#xff0c;感觉挺有意思的&#xff0c;然后在代码上随意做了一些更改&#xff0c;有了一些发现&#xff0c;把Lab通道的a通道值改为127左右&#xff0c;可以将绿色改为黄色&#xff0c;而对其他颜色的改动非常小&#xff0c;因此可以将春…...