前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx坑记录

nginx坑记录

作者头像
用户1215536
发布2019-09-25 12:03:16
5990
发布2019-09-25 12:03:16
举报

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

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

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

代码语言:javascript
复制
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
复制
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
复制
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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档