-10 +

nginx pool

nginx 内存布局结构图:

来看看相关的数据结构:

typedef struct {
    u_char               *last;
    u_char               *end;
    ngx_pool_t           *next;
    ngx_uint_t            failed;
} ngx_pool_data_t;


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;
};

我们先来看看 pool 的 create 结合上面的图来理解:

ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
{
    ngx_pool_t  *p;

	/**
	 * 像系统申请 size 大小的内存,并且以 NGX_POOL_ALIGNMENT 对其方式
	 */
    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
    if (p == NULL) {
        return NULL;
    }

	/**
	 * 这里讲 last 指向这块内存前面分配给的 ngx_pool_t 存放元数据
	 * 后面的内存, end 指向这块内存的最后位置。
	 */
    p->d.last = (u_char *) p + sizeof(ngx_pool_t);
    p->d.end = (u_char *) p + size;
    p->d.next = NULL;
    p->d.failed = 0;

	/**
	 * 这里表明了像 pool 申请 NGX_MAX_ALLOC_FROM_POOL 将不能全部利用
	 */
    size = size - sizeof(ngx_pool_t);
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;

    p->current = p;
    p->chain = NULL;
    p->large = NULL;
    p->cleanup = NULL;
    p->log = log;

    return p;
}

看完了 create,我们来看看当想 pool 中申请内存的算法:

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

	/**
	 * 申请的大小大于 max 时,使用 ngx_palloc_large 分配
	 */
    if (size <= pool->max) {

        p = pool->current;

        do {
        	// 从内存开始位置分配,以 NGX_ALIGNMENT 方式。
            m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);

			// 大小满足,分配
            if ((size_t) (p->d.end - m) >= size) {
                p->d.last = m + size;

                return m;
            }

            p = p->d.next;

        } while (p);

		// 若是整个链表都没有符合要求的内存块,想系统申请。 
		// 并且挂载到链表末尾
        return ngx_palloc_block(pool, size);
    }

    return ngx_palloc_large(pool, size);
}       

看完了小块内存的分配,我们来看看大块内存的分配:

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

	// 首先向系统申请 size 大小的内存
    p = ngx_alloc(size, pool->log);
    if (p == NULL) {
        return NULL;
    }

    n = 0;

	// 像 large 链表中查找,最大查找  3 次
    for (large = pool->large; large; large = large->next) {
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }

        if (n++ > 3) {
            break;
        }
    }

	// 申请 large 元数据内存。
    large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

	// 挂载到 large 链表终点头部。
    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

参考

关于我

85 后程序员, 比较熟悉 Java,JVM,Golang 相关技术栈, 关注 Liunx kernel,目前痴迷于分布式系统的设计和实践。 研究包括但不限于 Docker Kubernetes eBPF 等相关技术。

Blog

Code

Life

Archive