首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >nginx坑记录

nginx坑记录

作者头像
用户1215536
发布于 2019-09-25 04:03:16
发布于 2019-09-25 04:03:16
66600
代码可运行
举报
运行总次数:0
代码可运行

问题1: 配置解析过程使用ngx_cycle->pool申请内存保存配置,结果造成野指针。

背景:需求开发过程,有一些结构需要在配置解析阶段保存,然后可以动态修改。看原来的代码配置解析都是使用cf->pool进行内存申请,但动态修改的过程显然拿不到cf,于是想到了一个全局的内存池ngx_cycle->pool,想当然的认为ngx_cycle的生命周期是从配置解析开始到进程退出,期间是不会释放ngx_cycle->pool的,但其实是错误的,具体原因如下:

nginx的启动源码简化后如下所示,从代码中的注释可以看出原来配置解析前后ngx_cycle变量中的pool不是同一个:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int ngx_cdecl
main(int argc, char *const *argv)
{
    ngx_cycle_t      *cycle, init_cycle;
    ...
    ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
    init_cycle.log = log;
    ngx_cycle = &init_cycle;
    ...
    //配置解析前创建的pool,解析过程拿到的ngx_cycle->pool就是这个
    init_cycle.pool = ngx_create_pool(1024, log);
    if (init_cycle.pool == NULL) {
        return 1;
    }
    ...
    cycle = ngx_init_cycle(&init_cycle);
    if (cycle == NULL) {
        if (ngx_test_config) {
            ngx_log_stderr(0, "configuration file %s test failed",
                           init_cycle.conf_file.data);
        }

        return 1;
    }
    ...
    ngx_cycle = cycle;
}

其中配置解析在ngx_init_cycle里面完成

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
    ngx_cycle_t         *cycle, **old;
    ...
    log = old_cycle->log;
    //这个pool放在cycle中带出去,配置解析之后赋值给ngx_cycle
    pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
    if (pool == NULL) {
        return NULL;
    }
    pool->log = log;

    cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
    if (cycle == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

    cycle->pool = pool;
    cycle->log = log;
    cycle->old_cycle = old_cycle;
    .....
    配置解析
    ...
    return cycle;
}

<!-- p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px '.PingFang SC'} span.s1 {font: 12.0px 'Helvetica Neue'} -->

结论:ngx_cycle的周期不能简单的认为是从进程启动到退出,其pool在配置解析前后是两个值。

问题2:检视代码的时候发现ngx_array_t如果想被反复使用的话,需要注意其内存池的唯一性,不然会内存泄漏。

直接上nginx内核源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void
ngx_array_destroy(ngx_array_t *a)
{
    ngx_pool_t  *p;

    p = a->pool;

    if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
        p->d.last -= a->size * a->nalloc;
    }

    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
        p->d.last = (u_char *) a;
    }
}

结论:如果一个nginx的动态数组想在使用过程中调用ngx_array_destroy销毁,然后再ngx_array_init重复利用的话,那么一定要保证这个数组的内存池只给他自己用,否则,ngx_array_destroy中的两个判断都不成立,内存池的这块内存将无法释放。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
探索Nginx:深入理解Nginx基础组件的使用
Nginx自己实现了一个内存池组件。Nginx作为服务器,当客户端 TCP连接 &HTTP请求 到来时,Nginx会为该连接创建一个专属的内存池;这个内存池的生命周期是连接建立时创建,连接断开时销毁。客户端和Nginx通信的所有数据和操作(HTTP协议解析、HTTP数据解析等)都在内存池中完成。
Lion 莱恩呀
2025/01/05
3350
探索Nginx:深入理解Nginx基础组件的使用
【Nginx 源码学习】动态数组
1、Nginx的数组只存储比较小的数据 2、数组的元素长度在创建数组的时候就固定死了。但是数组个数,会自动扩容。 3、数组的数据结构和元素内存都会分配在Nginx的pool内存池上。 4、数组回收会去检查pool内存池,看是否可以将数组内存交还给内存池。
看、未来
2022/01/10
5990
【Nginx 源码学习】动态数组
【Nginx 源码学习】平滑重启,源码追踪
重启意味着新旧接替,在交接任务的过程中势必会存在新旧server并存的情形,因此,最主要的问题在于如何保证新旧server可以并存,如果重启前后的server端口一致,如何保证两者可以监听同一端口。
看、未来
2022/05/06
8420
【Nginx 源码学习】平滑重启,源码追踪
Nginx(10):数据类型 与 数据结构之 ngx_array
ngx_str_t的data成员指向的并不是普通的字符串,因为这段字符串未必会以’\0’作 为结尾,所以使用时必须根据长度len来使用data成员。
看、未来
2021/10/09
3240
Nginx(10):数据类型 与 数据结构之 ngx_array
Nginx的模块化设计
高度模块化的设计是 Nginx 的架构基础。Nginx主框架中只提供了少量的核心代码,大量强大的功能是在各模块中实现的。
mazhen
2023/11/24
5620
Nginx的模块化设计
Nginx(六):配置解析之location解析
nginx成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能。但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性。
烂猪皮
2021/01/28
2K0
Nginx(六):配置解析之location解析
初识nginx——内存池篇
初识nginx——内存池篇      为了自身使用的方便,Nginx封装了很多有用的数据结构,比如ngx_str_t ,ngx_array_t, ngx_pool_t 等等,对于内存池,nginx设计的十分精炼,值得我们学习,本文介绍内存池基本知识,nginx内存池的结构和关键代码,并用一个实际的代码例子作了进一步的讲解 一、内存池概述     内存池是在真正使用内存之前,预先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够用时,再继
magicsoar
2018/02/06
1.6K0
初识nginx——内存池篇
nginx源代码分析–event事件驱动初始化
2.进入函数ngx_init_cycle,调用每一个核心模块的create_conf
全栈程序员站长
2022/07/13
3770
nginx共享内存:共享内存的实现
nginx中, 作者为我们提供了方便共享内存的使用的接口,关于共享内存的使用在我之前的文章中有介绍。这次我们来研究一下nginx是如何实现的。 我们知道,如果我们的模块中要使用一个共享内存,需要调用ngx_shared_memory_add来创建共享内存。而ngx_shared_memory_add不会马上创建一个共享内存,它是先登记一下共享内存的使用信息,比如名称、大小等,然后在进程初始化的时候再进行共享内存的创建与初始化。 那么,ngx_shared_memory_add这个函数是将共享内存的分配登记在哪的呢?在ngx_cycle_s这个结构体中有一个成员,即ngx_cycle_s->shared_memory,它是一个list,用来保存所有登记的共享内存,这个list中保存的是ngx_shm_zone_t类型的数据。下面是ngx_shm_zone_t这个结构体的实现源码:
随心助手
2019/10/15
4.9K0
从nginx1.17.9源码理解nginx -s reload
使用nginx的时候,我们经常会使用nginx -s reload命令重启。下面我们就分析一下,执行这个命令的时候,nginx里发生了什么?我们从nginx的main函数开始。在main函数里,执行ngx_get_options函数命令行的初始化工作。 我们只看reload相关的逻辑。
theanarkh
2020/03/17
1.4K0
揭秘Nginx中如何使用红黑树优化数据操作
/src/http/modules/ngx_stream_log_module.c
Lion 莱恩呀
2025/01/13
3930
揭秘Nginx中如何使用红黑树优化数据操作
Nginx内存池
nginx里内存的使用大都十分有特色:申请了永久保存,抑或伴随着请求的结束而全部释放,还有写满了缓冲再从头接着写.这么做的原因也主要取决于Web Server的特殊的场景,内存的分配和请求相关,一条请求处理完毕,即可释放其相关的内存池,降低了开发中对内存资源管理的复杂度,也减少了内存碎片的存在.
后端技术探索
2019/05/07
1.3K0
nginx0.1.0之event模块初始化源码分析(1)
nginx模块初始化的流程在下面的代码中,核心模块的初始化,各核心模块首先在create_conf中创建保存配置的数据结构,然后在ngx_conf_parse中,通过解析命令,执行对应的命令处理函数,完成赋值和各核心模块的子模块初始化。最后,如果在ngx_conf_parse时,没有设置值,则执行init_conf函数进行默认初始化。
theanarkh
2019/03/06
5060
nginx1.17.9源码分析之线程池
我们发现事件驱动的软件都得配一个线程池。libuv和nginx都是。因为事件驱动的软件是单线程。但是有些事情总会引起线程阻塞。所以这个事情就不能放到主线程里做。这就是为什么事件驱动都要配一个线程池。把任务交给线程池中的线程。主线程继续执行。任务完成后通知主线程或者执行回调就行。 我们先看一下nginx线程池的架构。然后开始分析。
theanarkh
2020/03/31
6120
nginx1.17.9源码分析之线程池
内存池 及 nginx内存池
咳咳,这是知乎上的一个议题哈。我看了之后觉得,我不能等明天了,我今天就把nginx的内存池给剖了。
看、未来
2021/10/13
1.2K0
【C】高并发内存池设计
高并发内存池设计 高并发下传统方式的弊端 在传统C语言中,我们使用malloc、calloc、realloc、free来进行内存的申请分配与释放,函数原型如下。C++中则是new、delete。 void *malloc(size_t size); malloc在内存的动态存储区中分配了一块长度为size字节的连续区域返回该区域的首地址。 void *calloc(size_t nmemb, size_t size); 与malloc相似,参数size为申请地址的单位元素长度,nmem
半生瓜的blog
2023/05/13
1K0
【C】高并发内存池设计
Nginx vs Envoy vs Mosn 平滑升级原理解析
本文适合对 Nginx 实现原理比较感兴趣的同学阅读,需要具备一定的网络编程知识。
poslua
2020/01/02
3K1
Nginx vs Envoy vs Mosn 平滑升级原理解析
nginx平台初探(100%)
众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧。
用户5640963
2019/07/26
1.2K0
nginx平台初探(100%)
【Nginx 源码学习】Nginx 架构设计与主流程分析
1、nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个master进程和多个worker进程。 2、nginx采用了异步非阻塞的方式来处理请求。
看、未来
2022/05/06
1.3K0
【Nginx 源码学习】Nginx 架构设计与主流程分析
nginx1.17.9源码分析之管理配置的结构体(1)
之前对nginx0.1.0版本进行了部分代码的分析,接下来的时间,打算以最新版的源码为基础,重新开始分析nginx的实现。这是第一篇。
theanarkh
2020/03/17
5190
相关推荐
探索Nginx:深入理解Nginx基础组件的使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验