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_taddr去接受

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相关推荐

  1. Nginx源码阅读笔记-内存池的设计

    2019独角兽企业重金招聘Python工程师标准>>> nginx的内存池设计的比较简单了,一个内存池中分为两个部分: 超过max大小的内存分配,走大块内存分配,这部分内存管理由ng ...

  2. Nginx源码阅读:ngx_palloc 内存池

    Nginx源码阅读:ngx_palloc 内存池 一.内存池 二.大块 三.chunck(小块) 四.nginx内存池的结构图 五.源码阅读 1.`ngx_create_pool` 2.`ngx_de ...

  3. nginx源码分析之内存池与线程池丨nginx的多进程网络实现

    nginx源码分析之内存池与线程池 1. nginx的使用场景 2. nginx源码 内存池,线程池,日志 3. nginx的多进程网络实现 视频讲解如下,点击观看: [Linux后台开发系统]ngi ...

  4. nginx源码分析之内存池实现原理

    建议看本文档时结合nginx源码: 1.1   什么是内存池?为什么要引入内存池? 内存池实质上是接替OS进行内存管理,应用程序申请内存时不再与OS打交道,而是从内存池中申请内存或者释放内存到内存池, ...

  5. nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数

    前言 在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了.接下来我们先看看nginx的main函数干了些什么. main函数 这里先介绍一些下面会遇到的变量类型: ngx_int_t: t ...

  6. 【Nginx 源码学习】内存池 及 优秀案例赏析:Nginx内存池设计

    文章目录 关于设计内存池之我的想法 内存池案例 malloc 底层原理 jemalloc && tcmalloc Nginx内存池设计 基础数据结构 源码分析 ngx_create_p ...

  7. nginx源码阅读(一).综述

    前言 nginx作为一款开源的轻量级高性能web服务器,是非常值得立志从事服务端开发方向的人学习的.现今nginx的最新版本是nginx-1.13.6,代码量也日渐庞大,但是由于其核心思想并没改变,为 ...

  8. Nginx源码分析——ngx_pool_t内存池

    引言: C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存.追踪内存的分配.在不需要的时候释放内存--这个任务相当复杂.而直接使用系统调用malloc/free.new/delete进 ...

  9. Nginx源码阅读(ngx_http_process_request_line)

    ngx_http_process_request_line() static void ngx_http_process_request_line(ngx_event_t *rev) {ssize_t ...

最新文章

  1. matlab 2009a使用教程,实验一 安装MATLAB R2009a软件及其简单操作
  2. python每天学习30分钟系列
  3. c语言中管理员信息注册,regsvr32注册控件如果使用管理员身份执行
  4. 类加载器-启动类加载器
  5. html如何设置三列列宽相等,CSS分割宽度100%到3列
  6. ASN.1编解码:ORAN-E2AP分析
  7. firewalld的配置和使用
  8. 最爱的文本编辑器_VS Code——插件推荐整理
  9. vscode代码对比差异视图窗口切换方法(左右文件位置切换)
  10. rxbus 源码_RxBus 这个 RxBus 稳如老狗 @codeKK Android开源站
  11. python长度单位换算表_长度单位换算表大全
  12. _stdcall和_cdecl
  13. 回归分析结果表格怎么填_excel回归分析结果解读
  14. 爬取豆瓣电影排行榜top 250
  15. zapewnia stale poprawiając relacje związane
  16. 云服务器ecs是虚拟主机,云服务器ecs是虚拟主机吗
  17. python热图_python – 使用matplotlib中的3D数据生成热图
  18. 学以致用——Java源码——使用随机几何图形制作屏保程序(Screen Saver with Shapes Using the Java 2D API)
  19. Manjaro无法启动?别急,试试grub 命令加载系统。
  20. OSPF特殊区域之 完全NSSA区域

热门文章

  1. Unity3d游戏安装包 极限减少之 四分图、二分图 (NGUI向)
  2. 宇宙的灵界与生命层级
  3. 思维模型 波特五力模型
  4. 数据分析模型篇—波特五力模型
  5. php赋值 jq,jQuery的serializeArray对象赋值问题
  6. iOS 美女波浪图~ demo
  7. C#,数值计算的进化与发展——FORTRAN 77/80/95源程序 转C# 源程序的软件F2C#
  8. Protein Cell:基于R语言的微生物组数据挖掘最佳流程(大众评审截止14号晚6点)...
  9. 统计检验分析 (本文在chatGPT辅助下完成)
  10. halcon 方向梯度_KPL秋季赛半程梯度排行,DYG,AG稳坐T0,三队竞争两个胜者组名额...