oo_order()的对称配套函数,从打包值里取回objects。
实现
static inline unsigned int oo_objects(struct kmem_cache_order_objects x) { return x.x & OO_MASK; }x.x & OO_MASK:OO_MASK = (1 << 16) - 1 = 0xFFFF,取低 16 位。高 16 位的 order 被掩掉,只留 objects。
与oo_order()的对称
static inline unsigned int oo_order(struct kmem_cache_order_objects x) { return x.x >> OO_SHIFT; // 高 16 位 → order } static inline unsigned int oo_objects(struct kmem_cache_order_objects x) { return x.x & OO_MASK; // 低 16 位 → objects }| 函数 | 位操作 | 取哪部分 | 结果 |
|---|---|---|---|
oo_order(x) | >> OO_SHIFT(>>16) | 高 16 位 | order |
oo_objects(x) | & OO_MASK(&0xFFFF) | 低 16 位 | objects |
两者是oo_make()的逆操作,构成完整的编解码闭环:
oo_make(order, size) → (order << 16) | objects │ ┌───────────────┴───────────────┐ ▼ ▼ oo_order(x) oo_objects(x) x >> 16 x & 0xFFFF → order → objects
使用场景
oo_objects()在 SLUB 里用于获取一个 slab 页内的对象总数:
// 初始化新 slab 的 freelist unsigned int objects = oo_objects(s->oo); for_each_object(p, s, addr, objects) { set_freepointer(s, p, next); } // 计算统计信息 unsigned int total = oo_objects(s->oo) * nr_slabs; // sysfs 输出 objs_per_slab oo_objects(s->oo)典型出现位置:
allocate_slab()/new_slab():建 freelist 时确定循环次数。calculate_sizes():试算方案时比较对象数。kmem_cache_shrink()、统计输出:算总数。validate_slab():调试时校验对象数是否与slab->objects一致。
注意点
1. 结果受MAX_OBJS_PER_PAGE限制
#define MAX_OBJS_PER_PAGE 32767 /* since slab.objects is u15 */
oo_objects()理论上能返回最大 65535(16 位),但真实对象数受slab.objects是u15约束,上限 32767。calculate_order()在选方案时会保证不超过这个上限,所以实际返回值总是合法的。
2. 与order_objects()的区别
order_objects(order, size):临时计算,输入 order 和 size,返回理论对象数。oo_objects(x):从已打包的 OO 值提取,是缓存创建时定好的结果,之后直接查表式使用,不再重算。
后者更快、更一致:一旦calculate_order()选定了s->oo,后续所有地方都从它取,不会再出现“order 和 objects 不匹配”的问题。
3. 为什么用&而不是%或<<再>>
x.x & OO_MASK // 对 (x.x << OO_SHIFT) >> OO_SHIFT // 也能得到同样结果,但多一条指令
& OO_MASK是最直接、最高效的取低位方式,编译器也能识别为位域提取。
总结
oo_objects(x)用x.x & OO_MASK从打包的kmem_cache_order_objects中取回低 16 位的objects,与oo_order()(取高 16 位 order)对称,是oo_make()的逆操作之一,用于建 freelist、统计和 sysfs 输出等需要“一个 slab 能放多少对象”的场景。