Nginx系列二 slab分配器

nginx的slab分配器主要和共享内存(nginx自己实现的共享内存 采用mmap或者shm实现)一起使用,Nginx在解析完配置文件,把即将使用的共享内存全部以list链表的形式,对共享内存进行管理和划分。在nginx_cycle.c中

static ngx_int_t
ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn)
{
    u_char           *file;
    ngx_slab_pool_t  *sp;

    sp = (ngx_slab_pool_t *) zn->shm.addr;

    if (zn->shm.exists) {

        if (sp == sp->addr) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                      "shared zone \"%V\" has no equal addresses: %p vs %p",
                      &zn->shm.name, sp->addr, sp);
        return NGX_ERROR;
    }

    sp->end = zn->shm.addr + zn->shm.size;
    sp->min_shift = 3;
    sp->addr = zn->shm.addr;

.......

   ngx_slab_init(sp);//在共享内存建立完成之后开始初始化 slab分配器
可以看到共享内存的开始部分用来存储ngx_slab_pool_t。

slab对于内存的管理主要有两个方面:一个是page的管理(包括静态对齐和动态分配),另一个是对小于page的slot 小内存的管理,slot内存段的管理是琐碎而频繁。

slab中常变量的表述如下:

变量名                                值                   描述

ngx_pagesize                   4096           系统页大小

ngx_pagesize_shift            12          对应上项  4096=1<<12

pool->min_shirt                   3               固定值

pool->min_size                     8               最小分配8个字节


内存对齐能够减少不必要的碎片管理,另外内存对齐对内存访问的性能也有影响。参见这里.

整个slab管理器的定义如下

typedef struct ngx_slab_page_s  ngx_slab_page_t;

struct ngx_slab_page_s {
    uintptr_t         slab;  //32位表示page内128个字节的使用
    ngx_slab_page_t  *next;  下一个page
    uintptr_t         prev;
};


typedef struct {
    ngx_shmtx_sh_t    lock;

    size_t            min_size;
    size_t            min_shift;

    ngx_slab_page_t  *pages;
    ngx_slab_page_t   free;

    u_char           *start;
    u_char           *end;

    ngx_shmtx_t       mutex;

    u_char           *log_ctx;
    u_char            zero;

    unsigned          log_nomem:1;

    void             *data;
    void             *addr;
} ngx_slab_pool_t;

第一个问题:如何根据管理结构page获得对应的内存页的起始地址P呢?计算方法如下

 p = (page - pool->pages) << ngx_pagesize_shift;
            p += (uintptr_t) pool->start;


第二个问题,页面对齐可以提高内存的访问速度,slab是如何做到页面对齐的呢?  代码如下  实际上浪费了最后一个不满的page,在ngx_slab.c中

 m = pages - (pool->end - pool->start) / ngx_pagesize;
    if (m > 0) {
        pages -= m;
        pool->pages->slab = pages;
    }

动态页面的管理相对简单,既然所有闲置page都在链表上直接移除(分配时)就可以,  回收page的时候在头插到链表中,这里记住是头插。


业内slot的管理相对琐碎,不过slab的威力就在对琐碎频繁的小内存管理的能力。业内slot的管理,首先slab把slot划分为8,16,32,64,128,256,512,1024,2048,9条链表在ngx_slab_init()中:

    slots = (ngx_slab_page_t *) p;   //取得页首地址,实际上就是存放的page的管理struct
    n = ngx_pagesize_shift - pool->min_shift;  //12-3=9

    for (i = 0; i < n; i++) {
        slots[i].slab = 0;
        slots[i].next = &slots[i];
        slots[i].prev = 0;
    }

忘了说了,但超过2048个字节的申请,直接转向page的申请和管理不再由slot负责。


参考资料:

《深入剖析Nginx》高凯群



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值