Nginx源码阅读:共享内存ngx_shm_t和它的组织方式ngx_shm_zone_t、ngx_list_t
Nginx源码阅读:共享内存ngx_shm_t和它的组织方式ngx_shm_zone_t、ngx_list_t
- 一、Nginx中共享内存的结构图
- 二、Nginx中实现共享内存的部分
- 1、共享内存配置信息的结构体`ngx_shm_t`
- 2、分配共享内存`ngx_shm_alloc`
- 3、释放共享内存`ngx_shm_free`
- 三、管理共享内存(通过数据结构将它组织起来)
- 1、`ngx_shm_zone_t`
- 2、`ngx_list_t`
- 四、ngx_init_cycle中初始化共享内存和管理共享内存的数据结构
- 1、内存池分配(用于组织共享内存的数据结构)
- 2、共享内存分配
- 3、共享内存初始化的流程
- 五、使用共享内存
一、Nginx中共享内存的结构图
一个ngx_list_t
来组织所有的ngx_shm_zone_t
一个ngx_shm_zone_t
来管理一块共享内存
二、Nginx中实现共享内存的部分
1、共享内存配置信息的结构体ngx_shm_t
该结构体并非创建于共享内存空间中,而是通过内存池去创建这个结构体,通过这个结构体(共享内存的配置信息),调用ngx_shm_alloc
传入共享内存的配置信息ngx_shm_t
,从而创建一块共享内存空间。该结构体的addr就是指向共享内存的首地址
typedef struct {u_char *addr;//共享内存的起始地址size_t size;//共享内存的大小(字节)ngx_str_t name;ngx_log_t *log;ngx_uint_t exists; /* unsigned exists:1; */
} ngx_shm_t;
主要实现两个函数,分配共享内存和释放共享内存
ngx_int_t ngx_shm_alloc(ngx_shm_t *shm);
void ngx_shm_free(ngx_shm_t *shm);
2、分配共享内存ngx_shm_alloc
通过mmap
实现,获取一块共享内存的空间,并将共享内存的首地址用ngx_shm_t
的addr
去接受
ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{shm->addr = (u_char *) mmap(NULL, shm->size,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED, -1, 0);if (shm->addr == MAP_FAILED) {ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,"mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);return NGX_ERROR;}return NGX_OK;
}
3、释放共享内存ngx_shm_free
通过munmap
实现
void
ngx_shm_free(ngx_shm_t *shm)
{if (munmap((void *) shm->addr, shm->size) == -1) {ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,"munmap(%p, %uz) failed", shm->addr, shm->size);}
}
三、管理共享内存(通过数据结构将它组织起来)
1、ngx_shm_zone_t
ngx_shm_t
是对共享内存配置信息的结构体,那么ngx_shm_zone_t
是包含用户数据信息的共享内存配置的结构体(换句话说,就是ngx_shm_t
的基础上,引入了用户数据,包括如何初始化这块数据等操作)
同样,这个是(引入了用户信息)共享内存的配置信息,是通过内存池创建的。
struct ngx_shm_zone_s {void *data;//用户数据ngx_shm_t shm;//共享内存基本的结构体ngx_shm_zone_init_pt init;//用户数据的初始化函数(用于初始化shm这个结构体,但真正的共享内存并不在这创建)void *tag;//创建的共享内存模块void *sync;ngx_uint_t noreuse; /* unsigned noreuse:1; */
};
data
数据是作为init
初始化函数的参数。
2、ngx_list_t
ngx_list_t
就是用来管理ngx_shm_zone_t
的
ngx_list_t
中每隔chunck,分为n等分,每一块的大小是ngx_shm_zone_t
所需的大小。
Nginx源码阅读:ngx_list_t 链表
四、ngx_init_cycle中初始化共享内存和管理共享内存的数据结构
在ngx_init_cycle中
1、内存池分配(用于组织共享内存的数据结构)
通过内存池,初始化ngx_list_t
这个链表,一个chunck划分为n片区域,每片区域大小为一个ngx_shm_zone_t
结构体(用于配置共享内存信息的结构体)的大小。
if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))!= NGX_OK){ngx_destroy_pool(pool);return NULL;}
2、共享内存分配
if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {goto failed;}
3、共享内存初始化的流程
这里主要是遍历链表ngx_list_t,然后根据每个ngx_zone_t创建对应的共享内存
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{...part = &cycle->shared_memory.part;//取出共享内存链表中的一个chunck(part)shm_zone = part->elts;//取出chunck的共享内存区的首地址(chunck是分为一片片共享内存区)for (i = 0; /* void */ ; i++) {//这一步是为了初始化下一块chunckif (i >= part->nelts) {//一个chunck(part)有nelts个共享内存区if (part->next == NULL) {//如果是最后一个chunck,那么退出break;}part = part->next;//继续create下一块chunck(part)shm_zone = part->elts;//下一块chunck的共享内存部分头地址i = 0;//create下一块chunck,因此i复位为0}//出错的情况:如果chunck的某片共享内存区大小为0,那么就会失败if (shm_zone[i].shm.size == 0) {ngx_log_error(NGX_LOG_EMERG, log, 0,"zero size shared memory zone \"%V\"",&shm_zone[i].shm.name);goto failed;}shm_zone[i].shm.log = cycle->log;opart = &old_cycle->shared_memory.part;oshm_zone = opart->elts;//遍历chunck中每片共享内存区(ngx_shm_zone_t)for (n = 0; /* void */ ; n++) {if (n >= opart->nelts) {if (opart->next == NULL) {break;}opart = opart->next;oshm_zone = opart->elts;n = 0;}if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {continue;}if (ngx_strncmp(shm_zone[i].shm.name.data,oshm_zone[n].shm.name.data,shm_zone[i].shm.name.len)!= 0){continue;}if (shm_zone[i].tag == oshm_zone[n].tag&& shm_zone[i].shm.size == oshm_zone[n].shm.size&& !shm_zone[i].noreuse){shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
#if (NGX_WIN32)shm_zone[i].shm.handle = oshm_zone[n].shm.handle;
#endif//初始化 一片共享内存的结构体数据(chunck中的一部分)if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)!= NGX_OK){goto failed;}goto shm_zone_found;}break;}//初始化共享内存(真正的共享数据在这里,上面的一些结构如ngx_list、shm_zone,都是通过内存池创建的)if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {goto failed;}if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {goto failed;}if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {goto failed;}shm_zone_found:continue;}...
}
五、使用共享内存
ngx_shared_memory_add
返回ngx_shm_zone_t
,里面就包含了指向共享内存的指针。
它去使用或者创建一块共享内存,然后交给ngx_list_t去管理,因此这里使用了add
ngx_shm_zone_t *
ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
{ngx_uint_t i;ngx_shm_zone_t *shm_zone;ngx_list_part_t *part;part = &cf->cycle->shared_memory.part;//第一块chunckshm_zone = part->elts;//指向chunck中数据部分的首地址for (i = 0; /* void */ ; i++) {if (i >= part->nelts) {if (part->next == NULL) {break;}part = part->next;shm_zone = part->elts;i = 0;}if (name->len != shm_zone[i].shm.name.len) {continue;}if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len)!= 0){continue;}if (tag != shm_zone[i].tag) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"the shared memory zone \"%V\" is ""already declared for a different use",&shm_zone[i].shm.name);return NULL;}if (shm_zone[i].shm.size == 0) {shm_zone[i].shm.size = size;}if (size && size != shm_zone[i].shm.size) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"the size %uz of shared memory zone \"%V\" ""conflicts with already declared size %uz",size, &shm_zone[i].shm.name, shm_zone[i].shm.size);return NULL;}return &shm_zone[i];}shm_zone = ngx_list_push(&cf->cycle->shared_memory);//从共享内存中取出一个区域if (shm_zone == NULL) {return NULL;}shm_zone->data = NULL;shm_zone->shm.log = cf->cycle->log;shm_zone->shm.addr = NULL;shm_zone->shm.size = size;shm_zone->shm.name = *name;shm_zone->shm.exists = 0;shm_zone->init = NULL;//这块共享内存,可以自己初始化成想要的类型shm_zone->tag = tag;shm_zone->noreuse = 0;return shm_zone;
}
Nginx源码阅读:共享内存ngx_shm_t和它的组织方式ngx_shm_zone_t、ngx_list_t相关推荐
- Nginx源码阅读笔记-内存池的设计
2019独角兽企业重金招聘Python工程师标准>>> nginx的内存池设计的比较简单了,一个内存池中分为两个部分: 超过max大小的内存分配,走大块内存分配,这部分内存管理由ng ...
- Nginx源码阅读:ngx_palloc 内存池
Nginx源码阅读:ngx_palloc 内存池 一.内存池 二.大块 三.chunck(小块) 四.nginx内存池的结构图 五.源码阅读 1.`ngx_create_pool` 2.`ngx_de ...
- nginx源码分析之内存池与线程池丨nginx的多进程网络实现
nginx源码分析之内存池与线程池 1. nginx的使用场景 2. nginx源码 内存池,线程池,日志 3. nginx的多进程网络实现 视频讲解如下,点击观看: [Linux后台开发系统]ngi ...
- nginx源码分析之内存池实现原理
建议看本文档时结合nginx源码: 1.1 什么是内存池?为什么要引入内存池? 内存池实质上是接替OS进行内存管理,应用程序申请内存时不再与OS打交道,而是从内存池中申请内存或者释放内存到内存池, ...
- nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数
前言 在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了.接下来我们先看看nginx的main函数干了些什么. main函数 这里先介绍一些下面会遇到的变量类型: ngx_int_t: t ...
- 【Nginx 源码学习】内存池 及 优秀案例赏析:Nginx内存池设计
文章目录 关于设计内存池之我的想法 内存池案例 malloc 底层原理 jemalloc && tcmalloc Nginx内存池设计 基础数据结构 源码分析 ngx_create_p ...
- nginx源码阅读(一).综述
前言 nginx作为一款开源的轻量级高性能web服务器,是非常值得立志从事服务端开发方向的人学习的.现今nginx的最新版本是nginx-1.13.6,代码量也日渐庞大,但是由于其核心思想并没改变,为 ...
- Nginx源码分析——ngx_pool_t内存池
引言: C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存.追踪内存的分配.在不需要的时候释放内存--这个任务相当复杂.而直接使用系统调用malloc/free.new/delete进 ...
- Nginx源码阅读(ngx_http_process_request_line)
ngx_http_process_request_line() static void ngx_http_process_request_line(ngx_event_t *rev) {ssize_t ...
最新文章
- matlab 2009a使用教程,实验一 安装MATLAB R2009a软件及其简单操作
- python每天学习30分钟系列
- c语言中管理员信息注册,regsvr32注册控件如果使用管理员身份执行
- 类加载器-启动类加载器
- html如何设置三列列宽相等,CSS分割宽度100%到3列
- ASN.1编解码:ORAN-E2AP分析
- firewalld的配置和使用
- 最爱的文本编辑器_VS Code——插件推荐整理
- vscode代码对比差异视图窗口切换方法(左右文件位置切换)
- rxbus 源码_RxBus 这个 RxBus 稳如老狗 @codeKK Android开源站
- python长度单位换算表_长度单位换算表大全
- _stdcall和_cdecl
- 回归分析结果表格怎么填_excel回归分析结果解读
- 爬取豆瓣电影排行榜top 250
- zapewnia stale poprawiając relacje związane
- 云服务器ecs是虚拟主机,云服务器ecs是虚拟主机吗
- python热图_python – 使用matplotlib中的3D数据生成热图
- 学以致用——Java源码——使用随机几何图形制作屏保程序(Screen Saver with Shapes Using the Java 2D API)
- Manjaro无法启动?别急,试试grub 命令加载系统。
- OSPF特殊区域之 完全NSSA区域
热门文章
- Unity3d游戏安装包 极限减少之 四分图、二分图 (NGUI向)
- 宇宙的灵界与生命层级
- 思维模型 波特五力模型
- 数据分析模型篇—波特五力模型
- php赋值 jq,jQuery的serializeArray对象赋值问题
- iOS 美女波浪图~ demo
- C#,数值计算的进化与发展——FORTRAN 77/80/95源程序 转C# 源程序的软件F2C#
- Protein Cell:基于R语言的微生物组数据挖掘最佳流程(大众评审截止14号晚6点)...
- 统计检验分析 (本文在chatGPT辅助下完成)
- halcon 方向梯度_KPL秋季赛半程梯度排行,DYG,AG稳坐T0,三队竞争两个胜者组名额...