Nginx内存池源码刨析

Nginx 内存池刨析

实例源码刨析

#define BLOCK_SIZE  16   //每次分配内存块大小#define MEM_POOL_SIZE (1024 * 4) //内存池每块大小
	int i = 0, k = 0;int use_free = 0;ngx_pagesize = getpagesize();//获取系统的页大小//printf("pagesize: %zu\n",ngx_pagesize);char * ptr = NULL;for(k = 0; k< 1024 * 500; k++){ngx_pool_t * mem_pool = ngx_create_pool(MEM_POOL_SIZE);//创建池for(i = 0; i < 1024 ; i++){ptr = ngx_palloc(mem_pool,BLOCK_SIZE);if(!ptr) fprintf(stderr,"ngx_palloc failed. \n");else {*ptr = '\0';*(ptr + BLOCK_SIZE -1) = '\0';}}ngx_destroy_pool(mem_pool);}

一些函数和宏定义

#define NGX_ALIGNMENT   sizeof(unsigned long)    /* platform word 平台字节长*/
#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1)) /* b对齐为a的倍数*/
#define ngx_align_ptr(p, a)                                                   \(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))/*用于将指针 p 对齐到指定的对齐字节数 a*/
#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)

ngx_create_pool

创建线程池


ngx_pool_t * ngx_create_pool(size_t size)
{ngx_pool_t  *p;p = ngx_memalign(NGX_POOL_ALIGNMENT, size);if (p == NULL) {return NULL;}//它将 p 指针向后偏移 sizeof(ngx_pool_t) 字节,这样 p->d.last 就指向了内存块中除去 ngx_pool_t 结构体大小后的位置,即可用于分配的起始位置。//将 p 指向的内存块的 last 成员设置为指向当前内存块后面的一段内存的起始地址。//这段内存的大小为 sizeof(ngx_pool_t),即 ngx_pool_t 结构体的大小。//这样做是为了在这块内存中分配其他数据时,可以从这段内存的末尾开始分配,确保内存块的内存布局是连续的。p->d.last = (u_char *) p + sizeof(ngx_pool_t);//指向这块内存已使用区域的最后部分。//指向未使用区域的尾部p->d.end = (u_char *) p + size;//下一块内存块的地址p->d.next = NULL;//内存分配的失败次数p->d.failed = 0;//这行代码确定了内存池中可用于分配的最大内存大小。为了确保内存分配不会超出预先设定的阈值, size = size - sizeof(ngx_pool_t);p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;// 当前正在使用的数据块的指针p->current = p;//p->chain = NULL;p->large = NULL;//p->cleanup = NULL;//p->log = log;return p;
}

ngx_memalign

void * ngx_memalign(size_t alignment, size_t size)
{void  *p;int    err;err = posix_memalign(&p, alignment, size);//按照指定的对齐要求和大小分配内存块。if (err) {fprintf(stderr,"posix_memalign(%zu, %zu) failed", alignment, size);p = NULL;}if(debug) fprintf(stderr,"posix_memalign: %p:%zu @%zu", p, size, alignment);return p;
}

ngx_palloc分配内存

void *ngx_palloc(ngx_pool_t *pool, size_t size)
{//判断是分配内存池的内存还是单独分配一块内存位于大储存块区。
#if !(NGX_DEBUG_PALLOC)if (size <= pool->max) {return ngx_palloc_small(pool, size, 1);}
#endifreturn ngx_palloc_large(pool, size);
}
static 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) {p->d.last = m + size;return m;}p = p->d.next;} while (p);return ngx_palloc_block(pool, size);
}
  1. 定义一个指向内存池结构的指针p。
  2. 将当前内存池的指针赋值给p。
  3. 使用一个do-while循环来遍历内存池链表。
  4. 获取当前内存池的最后一个内存块的指针m。
  5. 如果align为真,则将m对齐到NGX_ALIGNMENT字节边界。
  6. 检查当前内存池中是否有足够的空间来分配size大小的内存块。如果有足够的空间,将内存块的指针m设置为分配内存块的起始地址,并将内存池的最后一个内存块的指针更新为m+size。然后返回m。
  7. 如果内存池中没有足够的空间,则将p指向下一个内存池,继续遍历内存池链表。
  8. 如果遍历完内存池链表仍然没有找到足够的空间,则调用ngx_palloc_block函数分配一个新的内存块,并将新分配的内存块的指针返回。

ngx_palloc_large


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);if (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);if (large == NULL) {ngx_free(p);return NULL;}large->alloc = p;large->next = pool->large;pool->large = large;return p;
}
  1. 首先,尝试使用ngx_alloc函数分配一块大小为size的内存。如果分配成功,则将该内存块的指针赋值给p
  2. 然后,遍历内存池中的large链表,查找一个alloc字段为NULL的节点。如果找到,则将分配的内存块的指针赋值给该节点的alloc字段,并返回该内存块的指针。
  3. 如果遍历了large链表3次仍然没有找到合适的节点,则跳出循环。
  4. 分配一个新的ngx_pool_large_t结构体,将其alloc字段赋值为分配的内存块的指针,并将该结构体添加到内存池的large链表中。
  5. 返回分配的内存块的指针。

函数ngx_palloc_large的用途是在Nginx的内存池中分配大块内存。在Nginx中,大块内存通常用于存储文件句柄、连接池等。

注意事项:

  1. 在使用ngx_palloc_large分配内存后,需要确保在适当的时候释放内存,以避免内存泄漏。
  2. 在使用ngx_palloc_large分配内存时,如果内存池中的large链表已经很长,可能会导致内存分配效率降低。因此,在分配大块内存时,可以考虑使用其他内存分配机制,如ngx_palloc函数。

void * ngx_alloc(size_t size)
{void  *p;p = malloc(size);if (p == NULL) {fprintf(stderr,"malloc(%zu) failed", size);}if(debug) fprintf(stderr, "malloc: %p:%zu", p, size);return p;
}

void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
{void              *p;ngx_pool_large_t  *large;p = ngx_memalign(alignment, size);if (p == NULL) {return NULL;}large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);if (large == NULL) {ngx_free(p);return NULL;}large->alloc = p;large->next = pool->large;pool->large = large;return p;
}
  1. 使用ngx_memalign函数尝试分配一块大小为size且对齐为alignment的内存。如果分配失败,直接返回NULL
  2. 使用ngx_palloc_small函数在内存池中分配一个ngx_pool_large_t结构体的空间,用于存储分配的内存块信息。如果分配失败,释放之前分配的内存,并返回NULL
  3. 将分配的内存块的指针存入ngx_pool_large_t结构体的alloc字段,并将该结构体添加到内存池的large链表中。
  4. 返回分配的内存块的指针。


void * ngx_pcalloc(ngx_pool_t *pool, size_t size)
{void *p;p = ngx_palloc(pool, size);if (p) {ngx_memzero(p, size);}return p;
}
  1. 首先,通过ngx_palloc函数尝试在内存池中分配一块大小为size的内存。如果分配成功,则将返回的指针赋值给p
  2. 如果p不为空,使用ngx_memzero函数将p指向的内存块初始化为全零。ngx_memzero函数的作用是将一块内存块的所有字节设置为零,这在初始化内存时非常有用,可以确保内存中的所有字节都被初始化为零,从而避免未初始化的内存导致的错误。
  3. 最后,返回p,即分配的内存块的指针。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot @DS注解 和 DynamicDataSource自定义实现多数据源的2种实现方式

前言 在实际的项目中&#xff0c;我们经常会遇到需要操作多个数据源的情况&#xff0c;SpringBoot为我们提供了多种实现多数据源的方式。本文将介绍两种常见的方式&#xff1a;使用DS注解实现多数据源的切换以及使用DynamicDataSource自定义实现多数据源的切换。 我们将分别介…

LINUX 入门 9

LINUX 入门 9 day11 20240507 耗时&#xff1a;120min 课程链接地址 第9章 百万并发的服务器 1 百万并发项目介绍与并发概念讲解 书接上回&#xff0c;把server做成并发量百万级的服务量 装4台虚拟机 vmware右下角可以设置虚拟机内存 内核 没敲&#xff0c;就看了一下&a…

Python 正则表达式 re . 符号

Python 正则表达式 re . 符号 正文示例1示例2 正文 用法说明&#xff1a;(点号) 在默认模式下&#xff0c;匹配除换行符以外的任意字符。 如果指定了 flags 参数 DOTALL &#xff0c;它将匹配包括换行符在内的任意字符。 示例1 import restr1 abcde print(re.search(., str…

[SWPUCTF 2021 新生赛]PseudoProtocols、[SWPUCTF 2022 新生赛]ez_ez_php

[SWPUCTF 2021 新生赛]PseudoProtocols 打开环境&#xff0c;提示hint.php就在这里&#xff0c;且含有参数wllm 尝试利用PHP伪协议读取该文件 ?wllmphp://filter/convert.base64-encode/resourcehint.php//文件路径php://filter 读取源代码并进行base64编码输出。 有一些敏…

scikit-learn实现单因子线性回归模型

1.是什么&#xff1a; 针对机器学习提供了数据预处理&#xff0c;分类&#xff0c;回归等常见算法的框架 2.基于scikit-learn求解线性回归的问题&#xff1a; 2.1.求解a&#xff0c;b对新数据进行预测&#xff1a; 2.2评估模型表现&#xff08;y和y’的方差MSE&#xff09;…

Python轴承故障诊断 (18)基于CNN-TCN-Attention的创新诊断模型

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Python轴承故障诊断 (一)短时傅里叶变换STFT Python轴承故障诊断 (二)连续小波变换CWT_pyts 小波变换 故障-CSDN博客 Python轴承故障诊断 (三)经验模态分解EMD_轴承诊断 …

【Linux系列】file命令

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

hadoop学习---基于Hive的数据仓库相关函数机制及其优化方案

Hive相关函数&#xff08;部分&#xff09;&#xff1a; if函数: 作用: 用于进行逻辑判断操作 语法: if(条件, true返回信息,false返回信息) 注意: if函数支持嵌套使用 select if(aa,’bbbb’,111) fromlxw_dual; bbbb select if(1<2,100,200) fromlxw_dual; 200nvl函数:…

25_Scala集合Tuple

文章目录 tuple1.元组定义2.Tuple元素访问3.如果元素的len2&#xff0c;称之为键值对对象&#xff0c;也称之为对偶元组4.补充上节Map5.Map集合遍历6.集合之间相互转化 tuple 概念&#xff1a;scala语言采用特殊的方式将无关的数据作为一个整体&#xff0c;组合在一起’ 1.元…

2024爆火的AI设备Rabbit R1到底是什么?有人说它是AI的iPhone时刻,有人说它是套壳的安卓

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

c++编程(10)——string

欢迎来到博主的专栏——c编程 博主ID&#xff1a;代码小豪 文章目录 <string>string类的接口构造、析构、与赋值重载构造函数赋值重载运算符 元素访问operator[] 容量修改器对string对象的操作迭代器 std::string是定义在c标准的一个类&#xff0c;定义在标准库<strin…

Unity 性能优化之图片优化(八)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、可以提前和美术商量的事1.避免内存浪费&#xff08;UI图片&#xff0c;不是贴图&#xff09;2.提升图片性能 二、图片优化1.图片Max Size修改&#x…

龙兵知识付费系统开发,教育机构如何利用小程序引流?

时代进步的好处是人们需求也越来越多&#xff0c;家长要求孩子学习十八般武艺&#xff0c;唱歌绘画舞蹈钢琴一样不能落下&#xff0c;各种培训需求只增不减&#xff0c;培训机构当然也越来越多。针对小孩子的才艺培训、针对大学生的考研考证培训、针对在职人士的技能培训和企业…

Momentum靶机系列Momentum2

先进行arp扫描&#xff1a; 获得渗透靶机的IP&#xff1a;192.168.13.142 扫描一下靶机的使用的端口&#xff1a; 具有tcp端口和http服务的80端口 可以扫描一下80端口的http服务&#xff1a; 可以发现一个网站&#xff1a;http://192.168.13.142 打开该网址&#xff1a; 查看…

Flink 部署模式

目录 概述 部署模式 会话模式&#xff08;Session Mode&#xff09; 单作业模式(Per-Job Mode) 应用模式(Application Mode) 运行模式&#xff08;资源管理模式&#xff09; Standalone运行模式 会话模式部署 应用模式部署 Yarn运行模式 会话模式部署 单作业模式部…

鸿蒙开发核心技术都有哪些【都是从零开始】

鸿蒙开发核心技术都有哪些&#xff1f;&#xff1a;【持续1年的时间公关鸿蒙技术】 我们能做哪些呢&#xff1f; 还是从UI业务开始吧 面试题1&#xff1a; 基于STAGE模型项目重构等问题 代理设计模式&#xff0c;业务与架构隔离 中介者模式&#xff0c;和代理设计模式的区别…

在 Vue3 中使用 styled-components

前言 随着组件化时代的兴起&#xff0c;前端应用开始采用组件级别的 CSS 封装&#xff1a;通过 JavaScript 声明和抽象样式&#xff0c;以提高组件的可维护性。在组件加载时动态加载样式&#xff0c;并动态生成类名&#xff0c;从而避免全局污染。 styled-components 是其中的…

湖仓一体 - Apache Arrow的那些事

湖仓一体 - Apache Arrow的那些事 Arrow是高性能列式内存格式标准。它的优势&#xff1a;高效计算&#xff1a;所有列存的通用优势&#xff0c;CPU缓存友好、SIMD向量化计算友好等&#xff1b;零序列化/反序列化&#xff1a;arrow的任何数据结构都是一段连续的内存&#xff0c;…

uniapp使用iconfont

1、把这两个文件在项目的静态资源目录下 2、修改iconfont.css文件 3、最后在app.vue中引入

软件测试—— 接口测试之通讯流程相关概念

通讯流程 1、协议 通讯规则 2、HTTP协议 协议的一种 3、接口规范文档 如何发请求的要求文档&#xff0c;获取什么响应内容的说明文档&#xff08;相当于菜单&#xff09;