ngx_slab_pool

本文详细介绍了Nginx的slab内存池工作原理,包括数据结构的初始化、内存的插入分配以及回收机制。slab内存管理主要分为小内存和大内存的分配,根据内存大小选择不同的分配策略,并通过slab_page_t数组保存分配信息。在回收内存时,会检查内存归属,更新分配状态,必要时释放整个page。
摘要由CSDN通过智能技术生成

slab:

slab是啥 借用百度百科的话来说,slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内存碎片,而且处理速度也太慢。而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免这些内碎片。slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当以后又要请求新的对象时,就可以从内存直接获取而不用重复初始化。

数据结构 和初始化

struct ngx_slab_page_s {
    uintptr_t         slab;
    ngx_slab_page_t  *next;
    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;


void
ngx_slab_init(ngx_slab_pool_t *pool)
{
    u_char           *p;
    size_t            size;
    ngx_int_t         m;
    ngx_uint_t        i, n, pages;
    ngx_slab_page_t  *slots;

    /* STUB */
    if (ngx_slab_max_size == 0) {
        ngx_slab_max_size = ngx_pagesize / 2;//最大为pagesize的一半
        ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));//计算exact size
        for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
            /* void */
        }
    }
    /**/

    pool->min_size = 1 << pool->min_shift;//最小大小

    p = (u_char *) pool + sizeof(ngx_slab_pool_t);//空闲内存的位置
    size = pool->end - p;//总内存的大小

    ngx_slab_junk(p, size);

    slots = (ngx_slab_page_t *) p;
    n = ngx_pagesize_shift - pool->min_shift;// 小内存的数量

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

    p += n * sizeof(ngx_slab_page_t);//继续偏移到页的位置

    pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));//计算页数

    ngx_memzero(p, pages * sizeof(ngx_slab_page_t));

    pool->pages = (ngx_slab_page_t *) p;//页数组指针

    pool->free.prev = 0;
    pool->free.next = (ngx_slab_page_t *) p;//刚开始空闲就是开始

    pool->pages->slab = pages;
    pool->pages->next = &pool->free;
    pool->pages->prev = (uintptr_t) &pool->free;

    pool->start = (u_char *)
                  ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t),
                                 ngx_pagesize);//设置开始位置

    m = pages - (pool->end - pool->start) / ngx_pagesize;//地址偏移后 看下有木有被浪费了空间
    if (m > 0) {
  //更新
        pages -= m;
        pool->pages->slab = pages;
    }

    pool->log_nomem = 1;
    pool->log_ctx = &pool->zero;
    pool->zero = '\0';
}

总结下:
首先根据min_shift 和ngx_pagesize的大小算出分配小内存slots数量。然后再根据start 和end 算出pages(多少页)。
所以说他们的内存结构是 ngx_salb_pool 后面跟着一个ngx_slab_page_t[slots]大小的数组,保存的是小内存信息,然后后面跟着一个ngx_slab_page_t[pages]大小的数组,保存的页信息,然后后面跟上的就是剩余的用来分配的内存了。

插入

插入还是先直接上注释的代码看来代码来看总结,应该就能理解了

static ngx_slab_page_t *
ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
{
    ngx_slab_page_t  *page, *p;

    for (page = pool->free.next; page != &pool->free; page = page->next) {

        if (page->slab >= pages) {
  //足够的内存

            if (page->slab > pages) {
  //还有剩的
                page[pages].slab = page->slab - pages;//还剩的数量
                page[pages].next = page->next;//下一个节点
                page[pages].prev = page->prev;//上一个节点

                p = (ngx_slab_page_t *) page->prev;//维护上下节点
                p->next = &page[pages];
                page->next->prev = (uintptr_t) &page[pages];

            } else {
  // 刚好用完
                p = (ngx_slab_page_t *) page->prev;
                p->next = page->next;
                page->next->prev = page->prev;//维护上下信息
            }

            page->slab = pages | NGX_SLAB_PAGE_START;
            page->next = NULL;
            page->prev = NGX_SLAB_PAGE;

            if (--pages == 0) {
  //只有一页
       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值