您的位置:首页 > 运维架构 > Nginx

nginx源码学习 内存池

2017-02-16 15:01 302 查看
1、内存池:

(1)宏定义:

//说明:每次最多可以从内存池申请的空间大小,ngx_pagesize代表操作系统内存页大小,x86中是4096字节为一页,所以这里是4095

#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)

//默认内存池大小

#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)

//默认内存池字节对齐

#define NGX_POOL_ALIGNMENT       16

//最小内存池大小,1个ngx_pool_t+2个ngx_pool_large_t+内存对齐

#define NGX_MIN_POOL_SIZE                                                     \

    ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \

              NGX_POOL_ALIGNMENT)

(2)结构体定义:

typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;

struct ngx_pool_cleanup_s {//文件缓冲

    ngx_pool_cleanup_pt   handler;//释放内存的回调,
//原型为typedef void (*ngx_pool_cleanup_pt)(void *data);

    void                 *data;//实际是ngx_pool_cleanup_file_t

    ngx_pool_cleanup_t   *next;//链表的下一个结点

};

typedef struct ngx_pool_large_s  ngx_pool_large_t;

struct ngx_pool_large_s {//大块内存链表

    ngx_pool_large_t     *next;//下一个结点

    void                 *alloc;//已分配内存块地址

};

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_MAX_ALLOC_FROM_POOL)

    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;//日志

};

typedef struct {

    ngx_fd_t              fd;//文件描述符

    u_char               *name;//文件名

    ngx_log_t            *log;//日志

} ngx_pool_cleanup_file_t;

(3)函数:

1)ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);

根据size创建内存池,初始化内存池结构,设置d.last为(u_char *) p + sizeof(ngx_pool_t)位置,即申请的内存块偏移该ngx_pool_t结构体后都是本块内存的数据区

2)void ngx_destroy_pool(ngx_pool_t *pool);

释放内存池,迭代释放cleanup中的所有结点,large中所有结点

3)void ngx_reset_pool(ngx_pool_t *pool);

重置内存池,释放large系列结点,,重置d.last为初始位置,d.failed为0,重置current为本结点,chain、large为null。

4)void *ngx_palloc(ngx_pool_t *pool, size_t size);

申请内存块,如果size小于内存块最大值(一页内存),则调用ngx_palloc_small,并设定内存对齐,否则调用ngx_palloc_large。做内存对齐。

5)void *ngx_pnalloc(ngx_pool_t *pool, size_t size);

同上,但是不做内存对齐

6)void *ngx_palloc_small(ngx_pool_t *pool, size_t size);

先取当前内存块使用位置d.last,并把该位置内存对齐后给临时变量m(对齐后可能m>d.last),如果d.end-m >=size,说明本块内存剩余空间足够分配,则d.last=m+size,返回m指针为分配空间的起始地址。

如果遍历完内存块都未分配到内存,则调用ngx_palloc_block创建size大小的新内存块

7)static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);

psize = (size_t) (pool->d.end - (u_char *) pool);//计算每块内存的实际大小,这个值应该<=max

申请psize大小的内存块,初始化内存块的d结构,这里有一个问题:在ngx_create_pool的时候,d.last += sizeof(ngx_pool_t),但是在这里d.last+=sizeof(ngx_pool_data_t)。这是因为ngx_create_pool返回的是内存池头结点,内部包含缓冲池其他链表指针,而ngx_palloc_block创建的是一个内存块,被添加到d链表的末尾,这块内存内部只需要包含内存块指针即可。然后从当前结点开始遍历内存池的内存块链表(d链表),找到d链表最后一个结点,把新内存块加到该结点后。

从这里可以看到failed的作用:执行到这里,说明current结点及其后面的结点已经连续4次分配内存失败,说明他们的空间不足,所以后移current结点,知道d.failed<=4的结点为止。

8)static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);

large结点本身空间是通过ngx_palloc_small开辟的,它的alloc指向了实际的数据空间(大小为size)。内存池在释放large数据空间时,并不删除large结点,而是free(alloc),alloc=null。如果在前四个large结点中找不alloc=null的结点,则新建一个large结点。

9)void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);

带内存对齐的large内存块申请,申请后直接添加到large链表

10)ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);

释放large结点中的数据块,但不删除large结点。由此可见,按页分配的内存是循环使用的,大于页的内存是一次性的。

11)void *ngx_pcalloc(ngx_pool_t *pool, size_t size);

内部调用ngx_palloc,但是多了初始化内存为0的过程

12)文件相关的内存操作

ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);

void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);

void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);

从上面的函数可以看出,内存块是没有直接释放接口的(即把last往回推),这个过程是在外部进行的,比如nginx的array,底层就是一个内存池,当数组中一个元素不使用时(需要释放),由array负责直接把last推回,源码:

void ngx_array_destroy(ngx_array_t *a)

{

    ......

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

        p->d.last -= a->size * a->nalloc;

    }

   ......

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: