Linux 内存管理之 SLUB分配器(1): Object-layout

SLUB分配器内容相较于SLOB会更多一些,分几次逐步学习整理;

Object即SLUB分配器中,分配给用户的基本单位,本小节即介绍Object 的layout构成(debug条件下),首先来看一张图,即本部分的核心内容:

1. 数据结构

​ SLUB中Object layout在calculate_sizes接口中计算得到:

  1. 在没有打开SLUB_DEBUG情况下obj中只有自身大小 + 对齐即可(fp嵌在开头);

  2. 打开debug功能后,会在obj前后增加一些结构,用于检测判断是否存在异常;

    1. 增加red zone、track结构、pading部分
    2. 经该接口后获取到layout如上图所示,后续增加数据转换部分,将red_left_pad放到左侧;

2. allocate_slab

当SLUB allocator申请一块内存作为slab 缓存池的时候,会将整块内存填充POISON_INUSE。如下图所示

3. layout 状态转换

free layout 填充数据如下:

  1. 通过检查red zone的数据可以判断是否在左右存在越界使用的情况;

    1. 左侧越界,即red_left_pad中值非0xcc
    2. 右侧越界,slab_red_zone中值非0xcc
  2. 通过检查obj中的数据 + red zone可以判断是否存在如下几种情况:

    1. use-uninitialised,即red zone中值为0xcc,而obj中值非0x6b0x6b…0x5a
    2. use-after-free,即red zone中值为0xbb,而obj中值非0x6b0x6b…0x5a

4. 关于object中red_left_pad位置调整的处理

从图中可以看到,我们在计算object size大小的时候,red_left_pad是放在最后添加的,而实际分配的时候该部分信息确是在object的最左侧的,在此位置也符合其实际功能,即判断object左侧是否存在越界行为,本部分介绍这块layout分配时的具体方法:

核心部分即上图中第3步,接下来详细看下这几个核心API:

  1. for_each_object_idx 宏

    #define for_each_object_idx(__p, __idx, __s, __addr, __objects) \for (__p = fixup_red_left(__s, __addr), __idx = 1; \__idx <= __objects; \__p += (__s)->size, __idx++)
    //这个宏也是关键部分,__addr为page中第一个object的地址,__objects为此slub page中object数量
    //则此宏解析完成后为,从1开始遍历直到objects这么多,其中每个object的地址均经过fixup_red_left的处理;
    
  2. fixup_red_left 操作

    void *fixup_red_left(struct kmem_cache *s, void *p)
    {//实现上述逻辑的核心函数,将object的起始位置向后偏移red_left_pad这么大的空间,用于填充red zone数据if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE)p += s->red_left_pad;return p;
    }
    
  3. init_object 初始化object结构操作

    static void init_object(struct kmem_cache *s, void *object, u8 val)
    {u8 *p = object;//关注这里,将上述fixup_red_left预留的空间填充上if (s->flags & SLAB_RED_ZONE) memset(p - s->red_left_pad, val, s->red_left_pad);if (s->flags & __OBJECT_POISON) {memset(p, POISON_FREE, s->object_size - 1);p[s->object_size - 1] = POISON_END;}if (s->flags & SLAB_RED_ZONE) memset(p + s->object_size, val, s->inuse - s->object_size);
    }
    

操作完成后其实是这个样子的:

5. 核心API源码:

calculate_sizes获取到当前object的layout状态和顺序,构造其大小:

/** calculate_sizes() determines the order and the distribution of data within a slab object.*/
static int calculate_sizes(struct kmem_cache *s, int forced_order)
{unsigned long flags = s->flags;size_t size = s->object_size; // kmem_cache中的size,即obj的正常大小(8Bytes ~ 8Kbytes)int order;size = ALIGN(size, sizeof(void *));//内嵌一个free pointer的指针#ifdef CONFIG_SLUB_DEBUG //默认在kernel中打开//如果存在alloc前使用或者free后使用,则不能自己poisonif ((flags & SLAB_POISON) && !(flags & SLAB_DESTROY_BY_RCU) && !s->ctor)s->flags |= __OBJECT_POISON;elses->flags &= ~__OBJECT_POISON;//留出 red zone的空间,一个指针的大小if ((flags & SLAB_RED_ZONE) && size == s->object_size)size += sizeof(void *);
#endifs->inuse = size;//这里是如果free pointer不能内嵌到第一个word中的话,就放在这里,一个指针的大小if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) || s->ctor)) {s->offset = size;size += sizeof(void *);}#ifdef CONFIG_SLUB_DEBUGif (flags & SLAB_STORE_USER)
//tracksize += 2 * sizeof(struct track);
#endifkasan_cache_create(s, &size, &s->flags);//kasan 内存检测
#ifdef CONFIG_SLUB_DEBUGif (flags & SLAB_RED_ZONE) {//padding & red_left_padsize += sizeof(void *);s->red_left_pad = sizeof(void *);s->red_left_pad = ALIGN(s->red_left_pad, s->align);size += s->red_left_pad;}
#endif
//alignsize = ALIGN(size, s->align);s->size = size;//layout到此构建结束,后续进行order排序    if (forced_order >= 0)//正常创建进来fortced_order为-1order = forced_order;elseorder = calculate_order(size, s->reserved);//计算order大小,这个order是根据kmem_cache的size算出来的;if (order < 0)return 0;s->allocflags = 0;if (order)s->allocflags |= __GFP_COMP;if (s->flags & SLAB_CACHE_DMA)s->allocflags |= GFP_DMA;if (s->flags & SLAB_RECLAIM_ACCOUNT)s->allocflags |= __GFP_RECLAIMABLE;s->oo = oo_make(order, size, s->reserved);//根据上述order和size,构造order_objects,高16bit为order,低16bit为counts->min = oo_make(get_order(size), size, s->reserved);if (oo_objects(s->oo) > oo_objects(s->max))s->max = s->oo;return !!oo_objects(s->oo);
}

关于其layout信息查看注释即可;

init_object,在分配给到kmem_cache使用时进行init_object初始化

static void init_object(struct kmem_cache *s, void *object, u8 val)
{u8 *p = object;if (s->flags & SLAB_RED_ZONE)//是否支持slub debug功能,如支持则在实际数据前后增加padmemset(p - s->red_left_pad, val, s->red_left_pad);//这个理解为前一个obj最后的那部分padif (s->flags & __OBJECT_POISON) {//alloc之后将obj的范围标记为free,即0x6bmemset(p, POISON_FREE, s->object_size - 1);p[s->object_size - 1] = POISON_END;//最后一个bit标记为end字符,即0xa5}if (s->flags & SLAB_RED_ZONE)//inuse中的剩余部分标记为传入的val值,这里的值传入基本就是active(0xcc)和inactive(0xbb)memset(p + s->object_size, val, s->inuse - s->object_size);
}

上述magic num定义:

#define SLUB_RED_INACTIVE    0xbb
#define SLUB_RED_ACTIVE     0xcc/* ...and for poisoning */
#define POISON_INUSE    0x5a    /* for use-uninitialised poisoning */
#define POISON_FREE 0x6b    /* for use-after-free poisoning */
#define POISON_END  0xa5    /* end-byte of poisoning */

5. 附录

路径 功能
https://elixir.bootlin.com/linux/v4.9/source/include/linux/poison.h 定义poison magic num
https://elixir.bootlin.com/linux/v4.9/source/mm/slub.c://elixir.bootlin.com/linux/v4.9/source/mm/slub.c slub源码
https://elixir.bootlin.com/linux/v4.9/source/include/linux/slab.h 定义debug 宏

参考

SLUB DEBUG原理 (wowotech.net)

Linux 内存管理之 SLUB分配器(1): Object-layout相关推荐

  1. Linux内存管理:slub分配器

    概述: 我们知道内核中的物理内存由伙伴系统(buddy system)进行管理,它的分配粒度是以物理页帧(page)为单位的,但内核中有大量的数据结构只需要若干bytes的空间,倘若仍按页来分配,势必 ...

  2. Linux内存管理之SLAB分配器

    注:本文讲述的SLAB相关代码是基于Linux内核v4.7,代码网址. 1.SLAB分配器的由来 在讲SLAB分配器之前先说两个概念: 内部碎片和外部碎片. 外部碎片指的是还没有被分配出去(不属于任何 ...

  3. Linux内存管理:内存分配:slab分配器

    <linux内核之slob.slab.slub> <Linux内核:kmalloc()和SLOB.SLAB.SLUB内存分配器> <Linux内存管理:内存分配:slab ...

  4. linux内存管理(六)-伙伴分配器

    linux内存三大分配器:引导内存分配器,伙伴分配器,slab分配器 伙伴分配器 当系统内核初始化完毕后,使用页分配器管理物理页,当使用的页分配器是伙伴分配器,伙伴分配器的特点是算法简单且高效,支持内 ...

  5. 【Linux 内核 内存管理】memblock 分配器编程接口 ⑤ ( memblock_free 函数 | memblock_remove_range 函数 )

    文章目录 一.memblock_free 函数分析 二.memblock_remove_range 函数分析 memblock 分配器提供了如下编程接口 : ① 添加内存 : memblock_add ...

  6. Linux内存管理:内存描述之内存页面page

    <Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> 目录 1 ...

  7. 深入理解Linux内存管理

    1.1 内存管理的意义 1.2 原始内存管理 1.3 分段内存管理 1.4 分页内存管理 1.5 内存管理的目标 1.6 Linux内存管理体系 2.1 物理内存节点 2.2 物理内存区域 2.3 物 ...

  8. 深入理解Linux内存管理(0.3)

    学习方法论 写作原则 标题括号中的数字代表完成度与完善度 0.0-1.0 代表完成度,1.1-1.5 代表完善度 0.0 :还没开始写 0.1 :写了一个简介 0.3 :写了一小部分内容 0.5 :写 ...

  9. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  10. Linux内存管理原理【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...

最新文章

  1. 你是如何自学 Python 的?
  2. WINDOWS下安装MYSQL—图文详解
  3. 题目 1885: [蓝桥杯][2017年第八届真题]分巧克力+二分
  4. swift int转string_Swift集合类型协议浅析(下)
  5. .NET 动态脚本语言Script.NET系列文章汇总 非常精彩的应用举例
  6. SpringHttpInvoker解析2-服务端实现
  7. string类有可以调换方向的函数吗_关于String类的split()方法
  8. Linux RPM软件包管理
  9. 锦囊5-斐波那契数列
  10. [WTL] 使用CImageList
  11. 怎么用PS为一寸证件照更换底色背景色
  12. MATLAB实现LSBR并采用卡方分析进行分析
  13. pat2020春季 7-2 The Judger (25分)
  14. 拳王公社:虚拟资源项目赚钱方法?前2种最常见,第3种鲜为人知
  15. mysql实验三报告总结_数据库安全性实验报告的总结(共9篇).docx
  16. 163邮箱苹果设置不成功_iphone手机,苹果手机如何登陆网易163邮箱
  17. aop:aspectj-autoproxy作用
  18. 软件工程导论第六版 第五章 总体设计知识点总结
  19. 我使用过的拼音输入法
  20. web开发工具选择,html零基础入门书籍

热门文章

  1. thinkphp5--多文件入口设置
  2. ubuntu 14.04 下hadoop2.9.1 64位编译
  3. 【iCore1S 双核心板_ARM】例程七:通用定时器实验——定时点亮LED
  4. 英语六级翻译训练:教育专题
  5. 如何JOPtionPane的showConfirmDialog对话框button设置监视器
  6. 39行代码实现JS HTML模板(轻量+高效+易用)
  7. 文本处理三剑客,正则表达式等
  8. 快速学习nodejs系列:四、nodejs特性1--单线程
  9. 从一个组件的实现来深刻理解 JS 中的继承
  10. espcms简约版的表单,提示页,搜索列表页