共享内存源码

代码版本:nginx 1.15.8

系统类型:64 位 linux

初始化共享内存管理结构

ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t));

nginx shared memory

创建共享内存

  • 注册一块共享内存

ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag);
    shm_zone = ngx_list_push(&cf->cycle->shared_memory); // 从共享内存管理链表中分配一个管理对象

一般在用到共享内存的模块中调用,如 ngx_http_limit_req_zone, ngx_http_lua_shared_memory_add

  • 分配内存空间

解析完配置后,统一为注册的共享内存分配内存空间

part = &cycle->shared_memory.part;
shm_zone = part->elts;
for (i = 0; /* void */ ; i++) { // 遍历共享内存管理链表
    if (i >= part->nelts) { // 链表的当前分片已遍历完
        if (part->next == NULL) {
            break;
        }
        part = part->next; // 开始遍历链表的下一个分片
        shm_zone = part->elts;
        i = 0;
    }
    shm_zone[i].shm.log = cycle->log;
    ngx_shm_alloc(&shm_zone[i].shm); // 映射内存空间
    ngx_init_zone_pool(cycle, &shm_zone[i]);
    shm_zone[i].init(&shm_zone[i], NULL);
}
ngx_shm_alloc(&shm_zone[i].shm); // 映射一块指定大小的匿名、共享、可读写内存空间
   shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
  • 初始化每块内存的管理结构

共享内存管理结构

ngx_init_zone_pool(cycle, &shm_zone[i]);
    sp = (ngx_slab_pool_t *) zn->shm.addr; // 开始位置分配一个 slab 管理器
    sp->end = zn->shm.addr + zn->shm.size; // 共享内存结束指针
    sp->min_shift = 3; // 一次最小申请 8 字节空间
    sp->addr = zn->shm.addr; // 共享内存起始指针
    ngx_shmtx_create(&sp->mutex, &sp->lock, file); // 初始化共享内存互斥锁
    ngx_slab_init(sp); // 初始化共享内存的 slab 管理器

注:slot 分级已申请内存的size - 1 的二进制位数减 min_shift 作为级别,如 size = 16,则二进制位数为4,slot = shift - pool->min_shift;,级别则为1

总共可分 8B, 16B, 32B, 64B, 128B, 256B, 512B, 1024B, 2048B 九级

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;

    pool->min_size = 1 << pool->min_shift; // 最小分配chunk 大小 8 Byte
    slots = (ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t)); // 分级数组
    p = (u_char *) slots;
    size = pool->end - p; // 剩余可用空间的大小
    ngx_slab_junk(p, size); // 初始化共享内存数据块
    n = ngx_pagesize_shift - pool->min_shift; // 计算可分的级数,page_size为4kb时对应的shift为12,min_shift=3
                                              // 则可分为 8,16,32,64,128,256,512,1024,2048 共九级
    for (i = 0; i < n; i++) {
        slots[i].slab = 0;
        slots[i].next = &slots[i];  // next 初始化时指向自己,使用时用于判断是否分配过该级别内存
        slots[i].prev = 0;
    }
    p += n * sizeof(ngx_slab_page_t); // 跳过 slot 分级数组区域

    pool->stats = (ngx_slab_stat_t *) p; // 与 slot 分级对应的统计结构
    ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t));
    p += n * sizeof(ngx_slab_stat_t); // 跳过统计结构
    size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t));
 
    pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t))); // 计算剩余空间还可分配出多少页
    pool->pages = (ngx_slab_page_t *) p; // pool->pages 指向第一个页管理器
    ngx_memzero(p, pages * sizeof(ngx_slab_page_t)); // 初始化每一页的管理器

    page = pool->pages;

    pool->free.slab = 0;
    pool->free.prev = 0; // 双向链表把空闲页串联起来,链表节点可能是多个连续的空闲页
    pool->free.next = page; // 指向可被分配的页管理器,初始指向第一片
 
    page->slab = pages; // 当前页管理器后面多少个连续的空闲页
    page->next = &pool->free;
    page->prev = (uintptr_t) &pool->free;

    // pool->start 指向实际存储数据的内存起始地址,并进行对齐
    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->last = pool->pages + pages;
    pool->pfree = pages; // 空闲页数
 
    pool->log_nomem = 1;
    pool->log_ctx = &pool->zero;
    pool->zero = '\0';
}

内存分配

  • 大块内存分配

  1. 待分配空间大于 2K,直接按整页分配
  2. 每个页都有一个管理器,当前页空闲时,如果后面连续的页也是空闲的,则用第一个页管理器统一管理,slab 记录管理的空闲页数
  3. 如果一次分配了多个页,统一用第一个页管理器管理,第一个页管理器中slab 记录管理的页数和 NGX_SLAB_PAGE_START 标记,其余页的 slab 标记 NGX_SLAB_PAGE_BUSY,每个页的 prev 记录页类型 NGX_SLAB_PAGE
  4. 被整页分配的页不会挂载到任何链表上,所以 page->next 为 NULL,在回收时会用到

大块内存分配1

大块内存分配2

void * ngx_slab_alloc_locked(ngx_slab_pool
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值