nginx源码学习 内存池

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
















猜你喜欢

转载自blog.csdn.net/blwinner/article/details/55258867