`
simohayha
  • 浏览: 1386240 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

nginx的内存管理

阅读更多
先来看内存池的实现,nginx的内存池实现的非常简单。

这里内存池的一些图表可以看老朱同学的slides :

http://blog.zhuzhaoyuan.com/2009/09/nginx-internals-slides-video/

当内存池初始化的时候(下面会分析到)ngx_poll_s只相当于内存池的一个头,保存了当前内存池的一些必要信息而已。

当从内存池存取数据的时候,nginx是分为两种类型来处理得,一种是小块数据,它是直接从内存池中取得数据,另一方面,当为大块数据时,它是直接malloc一块数据(也就是从内存池外部分配数据),然后保存这个指针到内存池。可以看到很多内存池,比如py的内存池实现,也基本是这个思想。这里的细节,我们将会在下面分析内存池相关函数的时候详细分析。

这里还有一个要注意就是这些子内存池和父内存池是不一样的,我们后面分析函数的时候会详细介绍。


大小块数据得分割线是你创建内存池时传递进来的size和页大小之间的最小值。


下面就是内存池的结构:

struct ngx_pool_s {
///数据区的指针
    ngx_pool_data_t       d;
///其实也就是内存池所能容纳的最大值。
    size_t                max;
///指向当前的内存池的头。
    ngx_pool_t           *current;
///这个主要是为了讲所有的内存池都链接起来。(他会创建多个内存池的)
    ngx_chain_t          *chain;
///这个链表表示大的数据块
    ngx_pool_large_t     *large;
///这个就是清理函数链表
    ngx_pool_cleanup_t   *cleanup;
    ngx_log_t            *log;
};


然后我们一个个来看上面的链表。首先是数据区的指针ngx_pool_data_t。

这个结构很简单,它就是包含了我们所需要操作这个内存池的数据的一些指针。

其中last表示当前的数据区的已经使用的数据的结尾。

end表示当前的内存池的结尾。也就是说end-last就是内存池未使用的大小。

我们要知道当我们从一个内存池请求一块内存时,如果此时内存池已经满掉,这是一般都是扩大内存池,而nginx中不是这么做的,它会直接再分配一个内存池,然后链接到data的next指针上。也就是说在nginx中,其实每个内存池都会包含一些子内存池。因此我们请求内存的时候都会遍历这些子内存池。

failed域主要是为了标记我们请求内存(小块内存)由于内存池空间不够,我们需要重新分配一个子内存池的次数。 下面分析函数的时候会再会看到这个域。

typedef struct {
    u_char               *last;
    u_char               *end;
//指向下一块内存池
    ngx_pool_t           *next;
///失败标记
    ngx_uint_t            failed;
} ngx_pool_data_t;


ngx_chain_t这里就先不介绍了,我们现在只需要知道它是与buf相关的。

然后是ngx_pool_large_s,它表示了大块的内存。可以看到这个结构非常简单,就是一个指针指向下一块large,一个alloc指向数据。

struct ngx_pool_large_s {
    ngx_pool_large_t     *next;
    void                 *alloc;
};


接下来是ngx_pool_cleanup_s,这个结构用来表示内存池中的数据的清理handler。

其中handler表示清理函数。
data表示传递给清理函数的数据。
next表示下一个清理handler,也就是说当destroy这个pool的时候会遍历清理handler链表,然后调用handler。

struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;
    void                 *data;
    ngx_pool_cleanup_t   *next;
}


通过ngx_create_temp_buf创建一个buff,然后通过ngx_alloc_chain_link创建一个chain,然后通过cl->buf = rb->buf;将buff链接到chain中.

下面就是pool的内存图,摘自老朱同学的nginx internal。


ok,接下来我们来通过分析具体的函数,来更好的理解pool的实现。

首先来看ngx_create_pool也就是创建一个pool。

这里我们要知道虽然我们传递进来的大小是size可是我们真正能使用的数据区大小是要减去ngx_pool_t的大小的。


///内存池的数据区的最大容量。
#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)

ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
{
    ngx_pool_t  *p;
///可以看到直接分配size大小,也就是说我们只能使用size-sizeof(ngx_poll_t)大小
    p = ngx_alloc(size, log);
    if (p == NULL) {
        return NULL;
    }

///开始初始化数据区。

///由于一开始数据区为空,因此last指向数据区的开始。
    p->d.last = (u_char *) p + sizeof(ngx_pool_t);
///end也就是数据区的结束位置
    p->d.end = (u_char *) p + size;
    p->d.next = NULL;
    p->d.failed = 0;

///这里才是我们真正能使用的大小。
    size = size - sizeof(ngx_pool_t);

///然后设置max。内存池的最大值也就是size和最大容量之间的最小值。
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;

///current表示当前的内存池。
    p->current = p;

///其他的域置NULL。
    p->chain = NULL;
    p->large = NULL;
    p->cleanup = NULL;
    p->log = log;
///返回指针。
    return p;
}


接下来我们来看如何从内存池中分配一块内存来使用。在nginx中有3个函数可以使用,分别是ngx_palloc,ngx_calloc,ngx_pnalloc。这三个函数的区别就是第一个函数分配的内存会对齐。第二个函数用来分配一块清0的内存,第三个函数分配的内存不会对齐。

由于这三个函数差不多,因此我们就只分析一个就够了。我们就来看ngx_palloc.


void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
    u_char      *m;
    ngx_pool_t  *p;

///首先判断当前申请的大小是否超过max,如果超过则说明是大块,此时进入large
    if (size <= pool->max) {

///得到当前的内存池指针。
        p = pool->current;

///开始遍历内存池,
        do {
///首先对齐last指针。
            m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);

///然后得到当前内存池中的可用大小。如果大于请求大小,则直接返回当前的last,也就是数据的指针。
            if ((size_t) (p->d.end - m) >= size) {
///更新last,然后返回前面保存的last。
                p->d.last = m + size;

                return m;
            }
///否则继续遍历
            p = p->d.next;

        } while (p);
///到达这里说明内存池已经满掉,因此我们需要重新分配一个内存池然后链接到当前的data的next上。(紧接着我们会分析这个函数)
        return ngx_palloc_block(pool, size);
    }

///申请大块。
    return ngx_palloc_large(pool, size);
}


接下来就来看ngx_palloc_block的实现,这个函数主要就是重新分配一块内存池,然后链接到当前内存池的数据区指针。

然后要注意这里重新new的这个内存池大小是和它的父内存池一样大的。

并且新得内存池只保存了ngx_pool_data_t这个结构,也就是说数据区直接跟在ngx_pool_data_t下面。


static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
{
    u_char      *m;
    size_t       psize;
    ngx_pool_t  *p, *new, *current;

///计算当前的内存池的大小。
    psize = (size_t) (pool->d.end - (u_char *) pool);

///再分配一个同样大小的内存池
    m = ngx_alloc(psize, pool->log);
    if (m == NULL) {
        return NULL;
    }

    new = (ngx_pool_t *) m;

///接下来和我们create一个内存池做的操作一样。就是更新一些指针
    new->d.end = m + psize;
    new->d.next = NULL;
    new->d.failed = 0;

///这里要注意了,可以看到last指针是指向ngx_pool_data_t的大小再加上要分配的size大小,也就是现在的内存池只包含了ngx_pool_data_t和数据。
    m += sizeof(ngx_pool_data_t);
    m = ngx_align_ptr(m, NGX_ALIGNMENT);
    new->d.last = m + size;

///设置current。
    current = pool->current;

///这里遍历所有的子内存池,这里主要是通过failed来标记重新分配子内存池的次数,然后找出最后一个大于4的,标记它的下一个子内存池为current。
    for (p = current; p->d.next; p = p->d.next) {
        if (p->d.failed++ > 4) {
            current = p->d.next;
        }
    }

///链接到最后一个内存池后面
    p->d.next = new;

///如果current为空,则current就为new。
    pool->current = current ? current : new;

    return m;
}


这里解释一下为什么这样设置current,这里的主要原因是我们在ngx_palloc中分配内存是从current开始的,而这里也就是设置current为比较新分配的内存。而当failed大于4说明我们至少请求了4次内存分配,都不能满足我们的请求,此时我们就假设老的内存都已经没有空间了,因此我们就从比较新的内存块开始。


接下来是ngx_palloc_large,这个函数也是很简单就是malloc一块ngx_poll_large_t,然后链接到主的内存池上。


static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
    void              *p;
    ngx_uint_t         n;
    ngx_pool_large_t  *large;

///分配一块内存。
    p = ngx_alloc(size, pool->log);
    if (p == NULL) {
        return NULL;
    }

    n = 0;
///开始遍历large链表,如果有alloc(也就是内存区指针)为空,则直接指针赋值然后返回。一般第一次请求大块内存都会直接进入这里。并且大块内存是可以被我们手动释放的。
    for (large = pool->large; large; large = large->next) {
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }
///这里不太懂什么意思。
        if (n++ > 3) {
            break;
        }
    }

///malloc一块ngx_pool_large_t。
    large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

///然后链接数据区指针p到large。这里可以看到直接插入到large链表的头的。
    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}


ok,分配看完了,我们来看释放。这里要知道在nginx中,只有大块内存提供了free接口,可以供我们收工释放,而小块内存是没有提供这个接口的。也就是说小块内存只有当整个内存池被desrtoy掉时,才会被释放。

这里一些简单的函数就不分析了。
比如ngx_pfree(ngx_pool_t *pool, void *p),这个函数就是从pool的large链表中找到p,然后free掉它。

ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)

这个函数也就是添加一个ngx_pool_cleanup_t到当前的pool上,然后返回,我们此时就能通过返回的结构来给对应的handler赋值。

而ngx_pool_cleanup_t这个主要是当内存池destroy的时候我们可能需要做一些清理工作,此时我们就能add这些清理handler到pool中,然后当内存池要释放的时候就会自动调用。

ok,现在来看pool 被free的实现。

这个函数主要是遍历large,遍历current,然后一一释放。

void
ngx_destroy_pool(ngx_pool_t *pool)
{
    ngx_pool_t          *p, *n;
    ngx_pool_large_t    *l;
    ngx_pool_cleanup_t  *c;

///先做清理工作。
    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);
        }
    }

///free大块内存
    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->d.next; /* void */; p = n, n = n->d.next) {
///直接free掉。
        ngx_free(p);

        if (n == NULL) {
            break;
        }
    }
}


通过上面我们可以看到在nginx中内存池中的小块数据是从来不释放的,这样就简化了内存池的操作。

接下来我们来看buf的实现。

buf分为两种类型,一种是file,一种是memory.因此这里会有文件的一些操作域。

可以看到buf相对于pool多了一个pos域(file_pos).这里我们要知道我们发送往套接字异或者其他的设备,我们这里会现将数据放到buf中,然后当设备或者套接字准备好了,我们就会从buf中读取,因此这里pos指针就是放到buf中的已经被执行的数据(也就是已经送往套接字)的位置。


struct ngx_buf_s {
///pos表示已经执行的数据的位置。
    u_char          *pos;
///last和上面内存池中last一样,也就是使用的内存的最后一个字节的指针
    u_char          *last;
///文件指针
    off_t            file_pos;
    off_t            file_last;
///buf的开始指针
    u_char          *start;         /* start of buffer */
    u_char          *end;           /* end of buffer */

///这里表示这个buf从属于那个模块。
    ngx_buf_tag_t    tag;
    ngx_file_t      *file;
    ngx_buf_t       *shadow;

///一些标记
    /* the buf's content could be changed */
    unsigned         temporary:1;

///在内存中是不能改变的。
    unsigned         memory:1;

///是否是mmap的内存
    unsigned         mmap:1;

    unsigned         recycled:1;

///是否文件。
    unsigned         in_file:1;
    unsigned         flush:1;
    unsigned         sync:1;
    unsigned         last_buf:1;
    unsigned         last_in_chain:1;

    unsigned         last_shadow:1;
    unsigned         temp_file:1;

    /* STUB */ int   num;
};



ok,接下来我们来看如何创建一个buf.在nginx中一般都是调用ngx_create_temp_buf来创建一个buf。函数很简单,就是从pool中分配内存然后初始化相关域。

ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
{
    ngx_buf_t *b;

///calloc一个buf,可以看到它调用的是calloc,也就是说都会清0.
    b = ngx_calloc_buf(pool);
    if (b == NULL) {
        return NULL;
    }

///然后从内存池中分配一块内存。并将这块内存链接到b->start.
    b->start = ngx_palloc(pool, size);
    if (b->start == NULL) {
        return NULL;
    }
///设置相关的域。

    b->pos = b->start;
    b->last = b->start;
///设置打消
    b->end = b->last + size;
    b->temporary = 1;

    return b;
}


然后我们来看chain的实现,chain其实也就是多个buf组合而成的。它主要是用来缓存一些未发出去的,或者接收的buf 以及 writev以及readv而存在的。

ok我们来看chain的实现,其实它的实现很简单,就是一个单链表。

struct ngx_chain_s {
///buf
    ngx_buf_t    *buf;
///下一个buf的指针。
    ngx_chain_t  *next;
};


然后来看如何创建一个chain。这里取得一个chain后直接返回给供其他模块使用:


ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t *pool)
{
    ngx_chain_t  *cl;

///取得pool的老的chain
    cl = pool->chain;
///如果chain已经存在,则直接返回这个chain,然后从pool的chain中删除这个chain。
    if (cl) {
        pool->chain = cl->next;
        return cl;
    }

///否则从内存池重新new一个chain。这里注意新建的这个chain是链接到pool的chain上的。
    cl = ngx_palloc(pool, sizeof(ngx_chain_t));
    if (cl == NULL) {
        return NULL;
    }

///然后返回
    return cl;
}



接下来就是两个重要的chain,它们其实就是对chain再进行了一次封装。

1 ngx_output_chain_ctx_t , 这个chain主要是管理输出buf。

2 ngx_chain_writer_ctx_t 这个主要是用在upstream模块。

因此我们主要来看ngx_output_chain_ctx_t。

ngx_output_chain_ctx_t,它包含了三种类型的chain,分别是in,free以及busy。

现在来介绍这几个重要的域:

buf : 这个域也就是我们拷贝数据的地方,我们一般输出的话都是从in直接copy相应的size到buf中。

in : 这个就是我们保存那些需要发送数据的地方。

free : 这个保存了一些空的buf,也就是说如果free存在,我们都会直接从free中取buf到前面的buf域。

busy :这个保存了已经发送完毕的buf,也就是每次我们从in中将buf读取完毕后,确定数据已经取完,此时就会将这个chain拷贝到busy中。然后将比较老的busy buf拷贝到free中。

output_filter是一个回调函数,用来过滤输出。

剩下的就是一些标记域。
typedef struct {
    ngx_buf_t                   *buf;
    ngx_chain_t                 *in;
    ngx_chain_t                 *free;
    ngx_chain_t                 *busy;

///相关的标记,是否使用sendfile,是否使用directio等等。。
    unsigned                     sendfile:1;
    unsigned                     directio:1;
#if (NGX_HAVE_ALIGNED_DIRECTIO)
    unsigned                     unaligned:1;
#endif
    unsigned                     need_in_memory:1;
    unsigned                     need_in_temp:1;

///内存池。
    ngx_pool_t                  *pool;
///每次从pool中重新alloc一个buf这个值都会相应加一。
    ngx_int_t                    allocated;
    ngx_bufs_t                   bufs;
///这个用来标记当前那个模块使用这个chain
    ngx_buf_tag_t                tag;

    ngx_output_chain_filter_pt   output_filter;
    void                        *filter_ctx;
} ngx_output_chain_ctx_t;



它对应的主要是ngx_output_chain函数。这个函数主要功能就是拷贝in chain的数据到buf域中。这个函数很复杂,我们这里简要分析一下:

ngx_int_t
ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
{
    off_t         bsize;
    ngx_int_t     rc, last;
    ngx_chain_t  *cl, *out, **last_out;

...........................................

    /* add the incoming buf to the chain ctx->in */

///拷贝in 到ctx的in chain中。
    if (in) {
        if (ngx_output_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
            return NGX_ERROR;
        }
    }

    out = NULL;
    last_out = &out;
    last = NGX_NONE;

///开始循环处理ctx-in chain.这里有两层循环。
    for ( ;; ) {

///开始遍历in
        while (ctx->in) {

  ///计算当前in的buf长度。这个长度也就是还没处理的数据长度。

            bsize = ngx_buf_size(ctx->in->buf);
..................................................
///如果buf为空,则我们需要给buf分配空间。

            if (ctx->buf == NULL) {
///这个函数很简单,主要是处理file buf,如果是file buf则会create一个buf链接到ctx
                rc = ngx_output_chain_align_file_buf(ctx, bsize);

                if (rc == NGX_ERROR) {
                    return NGX_ERROR;
                }

///如果是memory buf,都会到这里
                if (rc != NGX_OK) {
///如果free不为空,则我们从free chain中取得buf。
                    if (ctx->free) {

                        /* get the free buf */

                        cl = ctx->free;
                        ctx->buf = cl->buf;
                        ctx->free = cl->next;

                        ngx_free_chain(ctx->pool, cl);

                    } else if (out || ctx->allocated == ctx->bufs.num) {

                        break;

                    } 

///否则我们要重新create一个buf,然后链接到ctx,这里主要buf的大小和in chain的没有处理的数据一样大。
else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
                        return NGX_ERROR;
                    }
                }
            }

///从in chain拷贝数据到buf,并更新相关域。
            rc = ngx_output_chain_copy_buf(ctx);

            if (rc == NGX_ERROR) {
                return rc;
            }

            if (rc == NGX_AGAIN) {
                if (out) {
                    break;
                }

                return rc;
            }

    ///如果size为0,说明in chain中的第一个chain的数据已经被拷贝完了,此时删除这个chain。

            if (ngx_buf_size(ctx->in->buf) == 0) {
                ctx->in = ctx->in->next;
            }

///重新分配一个 chain
            cl = ngx_alloc_chain_link(ctx->pool);
            if (cl == NULL) {
                return NGX_ERROR;
            }

///链接buf到cl
            cl->buf = ctx->buf;
            cl->next = NULL;
            *last_out = cl;
            last_out = &cl->next;
            ctx->buf = NULL;
        }

        if (out == NULL && last != NGX_NONE) {

            if (ctx->in) {
                return NGX_AGAIN;
            }

            return last;
        }

///调用回调函数
        last = ctx->output_filter(ctx->filter_ctx, out);

        if (last == NGX_ERROR || last == NGX_DONE) {
            return last;
        }

///update 相关的chain,主要是将刚才copy完的buf 加入到busy chain,然后从busy chain中取出buf放到free chain中。
        ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
        last_out = &out;
    }
}


这里我只是简要的分析了下,详细的还需要接合其他模块来看。

最后来看ngx_chain_writer_ctx_t,这个主要用于ustream(由于没看这个模块,因此不理解这里为什么要多出来个writer).大概看了,觉得应该是ustream模块发送的数据量比较大,因此这里通过这个chain来直接调用writev来将数据发送出去。

typedef struct {
///保存了所要输出的chain。
    ngx_chain_t                 *out;

///这个保存了这次新加入的所需要输出的chain。
    ngx_chain_t                **last;
///这个表示当前连接
    ngx_connection_t            *connection;
    ngx_pool_t                  *pool;
    off_t                        limit;
} ngx_chain_writer_ctx_t;


这里我们要知道out是会变化的。每次输出后,这个都会指向下一个需要发送的chain。


ngx_int_t
ngx_chain_writer(void *data, ngx_chain_t *in)
{
    ngx_chain_writer_ctx_t *ctx = data;

    off_t              size;
    ngx_chain_t       *cl;
    ngx_connection_t  *c;

    c = ctx->connection;
///这里将in中的也就是新加如的chain ,全部复制到last中。也就是它保存了最后的数据。
    for (size = 0; in; in = in->next) {
....................................

///计算大小。
        size += ngx_buf_size(in->buf);


        cl = ngx_alloc_chain_link(ctx->pool);
        if (cl == NULL) {
            return NGX_ERROR;
        }

///加入last
        cl->buf = in->buf;
        cl->next = NULL;
        *ctx->last = cl;
        ctx->last = &cl->next;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
                   "chain writer in: %p", ctx->out);

///遍历out chain
    for (cl = ctx->out; cl; cl = cl->next) {

///计算所需要输出的大小
        size += ngx_buf_size(cl->buf);
    }

    if (size == 0 && !c->buffered) {
        return NGX_OK;
    }

///调用send_chain(一般是writev)来输出out中的数据。
    ctx->out = c->send_chain(c, ctx->out, ctx->limit);

........................

    return NGX_AGAIN;
}

1
0
分享到:
评论
2 楼 simohayha 2010-06-21  
cocobear 写道
你分析的nginx代码是哪个版本的呢?


0.7.65,  ,你也在研究nginx的源码?
1 楼 cocobear 2010-06-21  
你分析的nginx代码是哪个版本的呢?

相关推荐

    nginx slab内存管理精简源码及注释

    nginx的slab的内存管理方式,这种方式的内存管理在nginx中,主要是与nginx 的共享内存协同使用的。nginx的slab管理与linux的slab管理相同的地方在于均是利用了内存 的缓存与对齐机制,slab内存管理中一些设计相当...

    Nginx 全能HTTP+Web 指南 完整版pdf

    其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好。 Nginx全能指南是一本介绍Nginx服务器的书,首先,简要介绍Nginx的基本概念和作用,如反向代理、负载均衡等。然后,列举...

    nginx共享内存机制详解

    本文首先会讲解共享内存的使用方式,然后会讲解nginx是如何实现共享内存的管理的。 1. 使用示例 nginx声明共享内存的指令为: proxy_cache_path /Users/Mike/nginx-cache levels=1:2 keys_zone=one:10m max_size=...

    Nginx源码剖析之内存池,与内存管理

    其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,目前中国大陆使用nginx网站用户有:新浪、网易、腾讯,另外知名的微网志Plurk也使用nginx,以及诸多暂不曾得知的玩意儿...

    Nginx:取代apache的高性能服务器

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,Nginx是Apache服务器不错的替代品,它能够支持高达50 000个并发连接数的响应,运行稳定,且内存、CPU等系统资源消耗非常低。, 本书主要分为4个部分...

    Nginx源码剖析

    本书详细介绍了Nginx的进程模型,内存管理,request请求的解析,handler的处理等

    详解Nginx中基本的内存池初始化配置

    Nginx由其自己实现的内存池结构对内存进行管理,这里我们就来详解Nginx的基本内存池初始化配置,需要的朋友可以参考下

    Nginx Slab算法研究1

    摘要:Nginx设计了简单的内存池进行内存管理来降低开发中对内存资源管理的复杂度。Nginx 各进程间使用共享内存的方式共享数据,而对共享内存的内存池进行管理的

    Web服务器三剑客运维配置实战 Nginx+JVM+Tomcat+HTTP协议.zip

    ├─5.04 tomcat运维-tomcat日志说明-tomcat管理功能.mp4 ├─5.05 tomcat运维-server.xml配置文件注释.mp4 ├─5.06 tomcat运维-web站点部署.mp4 ├─5.07 tomcat运维-部署开源站点.mp4 ├─5.08 tomcat运维-tomcat...

    实战Nginx:取代Apache的高性能Web服务器

     近期,新浪、搜狐、网易、腾讯、金山、TOM、中华网、赛尔网络、上海九城等知名互联网公司的系统工程师、网络工程师招聘信息中,都加上了一条对Nginx配置管理经验的要求。Nginx作为新兴的Web服务器,目前的发展势头...

    nginx中共享内存的使用详解

    本文介绍在nginx的代码中与共享内存相关的功能,包括ngx_shmem与ngx_slab的使用与注意事项,但不包括ngx_slab中实现的内存管理算法。 ngx_shmem的使用 ngx_shmem.c/h文件只是对mmap()/munmap()系统调用或者shmget()...

    LNMP/Nginx 虚拟主机面板 AMH v5.0.zip

    欢迎使用LNMP/Nginx 虚拟主机面板 - AMH   01) 简单: 简洁精致,支持ssh、web在线轻松管理维护虚拟主机、MySQL、FTP。 02) 高效: 使用高性能Nginx服务器软件支持,面板基于AMH命令行运行,实现过程快速高效。 ...

    Nginx安装包

    最后我们还需要在web.xml中加入spring的session过滤器,我个人理解这个过滤器的作用是告诉spring来接管对session管理与创建工作。 1 &lt;!--session过滤器--&gt; 2 3 &lt;filter-name&gt;springSessionRepositoryFilter 4 ...

    Nginx 介绍及日常管理的详解

    Nginx 介绍及日常管理的详解 Nginx(发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发...

    实战Nginx.取代Apache的高性能Web服务器.2010 pdf

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,Nginx是Apache服务器不错的替代品,它能够支持高达50 000个并发连接数的响应,运行稳定,且内存、CPU等系统资源消耗非常低。  本书主要分为4个...

    基于ssm+shiro+redis+nginx tomcat服务器集群管理项目源码+项目说明.zip

    基于ssm+shiro+redis+nginx tomcat服务器集群管理项目源码+项目说明.zip Introduction ==== 1.搭建一个最简洁,模块划分最明确的ssm+swargger+shiro+redis+nginx整合项目,采用maven作为构建工具,在有新项目开发时...

    linux下安装nginx(图文教程)

    其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好。以下主要介绍linux下安装nginx。 linux系统为Centos 64位 简介 一、Linux安装软件常用方法 1、rpm(或pkg)安装,...

    《APMServ 5.2.6》:一键快速搭建Apache+PHP+MySQL+Nginx+Memcached+ASP平台的绿色软件

     Memcached 1.2.4 【key-value内存缓存系统】  MySQL 5.1.28 【MySQL数据库服务器】  MySQL 4.0.26 【MySQL数据库服务器】  phpMyAdmin 2.11.9.2 【MySQL数据库在线管理工具】  eAccelerator 0.9.5.3 【PHP脚本...

Global site tag (gtag.js) - Google Analytics