公告:本站提供编程开发方面的技术交流与分享,打造最佳教程网,希望能为您排忧解难!

nginx源代码分析:内存分配

nginx源代码分析:内存分配

更新时间:2013-03-16 17:06:10 |

Nginx的内存分配一共分成两层,第一层是对malloc()等函数进行了第一层的封装,例如malloc()对应的被封装成ngx_alloc()函数。
 

我们看一下ngx_alloc的源代码:

void *
ngx_alloc(size_t size, ngx_log_t *log)
{
    void *p;

    p = malloc(size);
    if (p == NULL) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                      "malloc() %uz bytes failed", size);
    }

    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);

    return p;
}

封装的好处在于对失败的内存分配进行了错误处理。

在这个基础上,nginx内存进行了第二层封装,也就是内存池



在Nginx的不同代码里都有对创建内存池的过程,我们总结一下:

init_cycle.pool = ngx_create_pool(1024, log);
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); // NGX_CYCLE_POOL_SIZE = 16384
ha.temp_pool = ngx_create_pool(16384, cf->log);
pool = ngx_create_pool(16384, cf->log);
r->pool = ngx_create_pool(cscf->request_pool_size, c->log);
pool = ngx_create_pool(2048, s->connection->log);

16384实际上是16k内存,多数是16K为一个pool


因此在Nginx中创建了若干个pool的单向链表结构。

其中next指向同等大小的下一个pool,每个pool都用一个end指向自己的池底。


以下是ngx_pool_s的结构定义:

struct ngx_pool_s {
    u_char               *last;
    u_char               *end;
    ngx_pool_t           *current;
    ngx_chain_t          *chain;
    ngx_pool_t           *next;
    ngx_pool_large_t     *large;
    ngx_pool_cleanup_t   *cleanup;
    ngx_log_t            *log;
};

每分配一个pool,它的第一个元素总是ngx_pool_t结构,我们在图中用header进行表示。

我把pool当中的小块,分成了item、large和cleanup三种,当待分配空间已经超过了池子自身大小,nginx也没有别的好办法,只好按照你需要分配的大小,实际去调用malloc()函数去分配,例如池子的大小是1K,待分配的大小是1M。实际上池子里只存储了ngx_pool_large_t结构,这个结构中的alloc指针,指向被分配的内存,并把这个指针返回给系统使用。

当然我们不希望large这种事太多,否则没有启到池子的作用。

当我们使用ngx_pool_cleanup_add()添加回收机制的时候,会在池子中分配一个ngx_pool_cleanup_t结构,并让header的cleanup指到这个结构上,这个结构的指针被返回给系统。

系统会对handler赋值一个反射函数,当我们调用ngx_destroy_pool()函数的时候,进行回收相关的处理。

当一个池子无法分配足够的空间,会继续调用ngx_create_pool()创建新的池子。

内存池的释放

ngx_destroy_pool()用来释放内存池,一共分三步:

第一步、在释放前先对业务逻辑进行释放前的处理

    for (c = pool->cleanup; c; c = c->next) {
        if (c->handler) {
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
                           "run cleanup: %p", c);
            c->handler(c->data);
        }
    }

第二步、释放large占用的内存

    for (l = pool->large; l; l = l->next) {

        ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);

        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

第三步、释放所有的池子

for (p = pool, n = pool->next; /* void */; p = n, n = n->next) {
        ngx_free(p);

        if (n == NULL) {
            break;
        }
}
最佳教程网

最大的技术交流平台 www.goodxyx.com© CopyRight 2011-2013, All Rights Reserved

浙ICP备11033019号