10 nginx 中的 slab
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10 nginx 中的 slab相关的知识,希望对你有一定的参考价值。
前言
这里主要是描述 nginx 中的 slab 内存分配相关
slab 在很多的地方都有使用, 比如 linux, nginx, netty 等等
主要的作用是 内存管理, 复用
简略 nginx 中的 slab 的流程
# slab related
void* poolPtr = malloc(2048);
ngx_slab_pool_t *pool = (ngx_slab_pool_t *)poolPtr;
ngx_slab_init(pool);
void* allocatedPtr = ngx_slab_alloc(pool, 36);
int x = 0;
x += 1;
poolPtr = allocatedPtr;
# 如果 sz 的 shift 为 ngx_slab_exactly_shift
则使用 page->slab 来存储当前 page 的 n 个 entry 是否被使用
bitmap 的数量为 1, 使用 page->slab 来表示
前面 m 个 entry 为 bitmap 的位置, m 的计算方式为 (ngx_page_size / (1 << shift)) / ((1 << shift) * 8)
(ngx_page_size / (1 << shift)) 为 entry 的数量
每一个 entry 中存在 (1 << shift) 个 byte, 合计 ((1 << shift) * 8) bit
因此需要的 m 为 (ngx_page_size / (1 << shift)) / ((1 << shift) * 8)
在计算 bitmap[i] 的时候, n + 1 是因为当前申请了一块空间, 将这块额外的空间 置为 used
page->slab 中存放的是 shift
# 如果 sz 的 shift < ngx_slab_exactly_shift
则使用 page->bitmap 来存储当前 page 的 n 个 entry 是否被使用
bitmap 的数量计算来自于 (ngx_page_size / (1 << shift)) / (8 * sizeof(uint_ptr))
# 如果 sz 的 shift > ngx_slab_exactly_shift
如果是 shift > ngx_slab_exactly_shift, 则能够存放的 entry 数量必定小于等于 32
page->slab 高32bit 存放的是 bitmap
page->slab 低32bit 存放的是 shift
ngx_slab_exactly_shift = 6
ngx_page_size = 4096
page->slab 类型为 uint_ptr 长度为 64
ngx_slab_exactly_shift 为 6, 一个空间占用 64byte, uint_ptr 有 64 bit, 总共可以表示 4096 byte, 因此 ngx_slab_exactly_shift 为 6
nginx 中的 slab 空间的分配
1. 如果 size 大于 ngx_slab_max_size[为 1/2 * pageSize]
直接以页为单位 来分配空间
2. 计算 shift 以及 slot
shift 指代的是存储 size 的最小的 2的n次幂空间 的对数[即为n]
slot 指代的是当前 slab 中存储当前 shift 对应的 slot
假设需求空间为 27b, page->min_shift 为 3, 则存储 27b 的最小的 2的n次幂空间 为 32
shift 为 5
page->min_shift 为 3 表示最小以 8b 为单位申请空间, 那么这里的 slot 为 2
slot[0] 存放的是申请的 8b 的 page 列表, slot[1] 存放的是申请的 16b 的 page 列表, slot[2] 存放的是申请的 32b 的 page 列表
3. 假设我们需要新申请一个 page
3.1 假设 shift < ngx_slab_exact_shift[为6], 即 size < 64b
那么此时维护当前 page 的 bitmap 需要使用前 n 个 entry[每一个 entry 占用 (2 << shift) byte]
当前 page 总共会有 (ngx_pagesize / (2 << shift)) 个 entry
那么 n 为 ((ngx_pagesize / (2 << shift)) / ((2 << shift) * 8))
然后下面初始化 bitmap, 下面的 bitmap[0] ~ btimap[i] 的处理, 指代的是 bitmap 中前 (n + 1) 个 entry 已经被使用[因为 bitmap 本身需要占用这一部分的空间, 分配空间的时候不能分配这部分空间, 标记为已经使用]
bitmap[i+1] - bitmap[map-1] 指代的是 n+1 以后的 entry 可用
然后 下面 page-> slab 记录的是 shift, 更新 slot 的相关引用, 以及对应的统计 等等
返回 bitmap 占用空间之后的第一个 entry 给调用方
画个图来配合理解一下
3.2 假设 shift = ngx_slab_exact_shift[为6], 即 size = 64b
使用 page->slab 来维护当前 page 的 bitmap
返回当前 page 的起始空间给调用方
3.3 假设 shift > ngx_slab_exact_shift[为6], 即 size > 64b
那么此时 能够存储的 entry 的数量一定是 <= 32, 因此使用 page->slab 的高 32bit 存放 bitmap, 低 32 bit 存放 shift
返回当前 page 的起始空间给调用方
4. 假设是基于已有的 page 进行空间分配
4.1 假设 shift < ngx_slab_exact_shift[为6], 即 size < 64b
轮询 bitmap 找到可以分配的空间的索引, 更新给定的bitmap[idx]为已经使用, 然后将给定的空间的地址返回回去
如果当前 page 空间已经被全部使用, 从 slots[slot] 中 unlink
4.2 假设 shift = ngx_slab_exact_shift[为6], 即 size = 64b
轮询 bitmap 找到可以分配的空间的索引, 更新给定的bitmap[idx]为已经使用, 然后将给定的空间的地址返回回去
如果当前 page 空间已经被全部使用, 从 slots[slot] 中 unlink
4.3 假设 shift > ngx_slab_exact_shift[为6], 即 size > 64b
轮询 bitmap 找到可以分配的空间的索引, 更新给定的bitmap[idx]为已经使用, 然后将给定的空间的地址返回回去
如果当前 page 空间已经被全部使用, 从 slots[slot] 中 unlink
nginx 中的 slab 空间的释放
1. 根据地址确定属于哪一个 page, 并且确定 page 的类型
根据 p 的偏移进行计算 所在 page 的索引, 然后根据 page 中存储的类型信息确定类型
2. 假设 类型为 SMALL, 即 size < 64b
根据 p 计算 页内 偏移, 计算当前元素的 entry 的索引
查询 bitmap 当前 entry 是否已经被释放
如果还未被释放, 释放当前 entry, link 当前 page 到 slots[slot]
如果当前 page 空间已经全部被释放, 归还 page 到 free, 更新 stats
3. 假设 类型为 EXACTLY, 即 size = 64b
根据 p 计算 页内 偏移, 计算当前元素的 entry 的索引
查询 bitmap 当前 entry 是否已经被释放
如果还未被释放, 释放当前 entry, link 当前 page 到 slots[slot]
如果当前 page 空间已经全部被释放, 归还 page 到 free, 更新 stats
4. 假设 类型为 BIG, 即 size > 64b
根据 p 计算 页内 偏移, 计算当前元素的 entry 的索引
查询 bitmap 当前 entry 是否已经被释放
如果还未被释放, 释放当前 entry, link 当前 page 到 slots[slot]
如果当前 page 空间已经全部被释放, 归还 page 到 free, 更新 stats
4. 假设 类型为 PAGE, 即 size > pageSize/2
nginx 中 slab 的内存布局
pool 中内存边界为 [&pool, pool->end]
n 为 ngx_pagesize_shift - pool->min_shift, 总共的 slot 的数量
pages 为 ((pool->end - &pool) - (n * sizeof(ngx_slab_page_t)) - (n * sizeof(ngx_slab_stat_t))) / (ngx_page_size + sizeof(ngx_slab_page_t))
ngx_slab_pool_t 的元数据
n 个 slots
n 个 slot_page
pages 个 slot_stats
pages 个 page 存储真实的数据
完
以上是关于10 nginx 中的 slab的主要内容,如果未能解决你的问题,请参考以下文章