Linux 内存管理之SLUB分配器三 [ Object分配逻辑 ]

内存是需要被操作系统管理的资源,我们在不同层次的管理本质是一样的:

  1. 以怎样的数据结构管理空闲资源,这部分在上一小节中已经整理完成;
  2. 以怎样的算法分配/释放资源,本小节主要整理分配逻辑部分;

1. 框架

  1. 数据结构框图:

  2. 三级缓存结构:

    基于上述数据结构,可以理解SLUB为三级缓存结构:

    1. 第一层,在freelist中寻找,速度最快;
    2. 第二层,在kmem_cache_cpu中寻找,需要切换page;
    3. 第三层,在kmem_cache_node中寻找;

    与其他缓存机制一样,越向下寻找,资源消耗越多;

    即将freelist、kmem_cache_cpu 、kmem_cache_node结构理解为三层缓存的结构,依次搜索空闲的object,直到找到为止;

2. 关于分配的四种case

整体逻辑都在上述图里了,这里详细介绍下各种case的细节处理,其核心入口函数为:slab_alloc_node;

2.1 基于freelist分配

本部分没有什么特别的,实际只做了两件事情:

  1. 将c->freelist 指向的object返回;
  2. 将next_object赋值给到 c->freelist;

2.2 基于kmem_cache_cpu分配

如果上述c->freelist中object已经被分配完,则此时c->freelist为NULL,我们需要到kmem_cache_cpu中分配,分为两种情况:

  1. c->page是存在的,首先从此page中搜索;
  2. 如上述不存在则从kmem_cache_cpu->partial链表中搜索;

2.2.1 c->page中分配

当2.1中object为空时,即会进入此流程:

  1. 获取page中的freelist指针并返回;

    1. 更新page->freelist为NULL,这个细节需要注意;
  2. 获取到page中下一个空闲的object,并将其赋值给到kmem_cache_cpu->freelist,则下次可以直接获取;

2.2.2 c->partial中分配

另外需要注意的是,2.2.1 虽然有整理出来code流程,但是理论上是不存在这种可能性的,因为每次从page中获取到freelist后,page->freelist都为NULL,即这里get_freelist基本是失败的,详情如下:

此流程中c->freelist和page->freelist都为NULL(按照设计流程在freelist为空时就是这种情况)

  1. 将c->page设置为NULL,进入c->partial链表中搜索;
  2. 更新page 和 partial的指针,接下来的处理与2.2.1中相同;

2.3 基于kmem_cache_node分配

如果上述c->partial 为NULL,即当前的kmem_cache_cpu上没有page了,则需要从node中分配:

这里的处理逻辑也很简单:

  1. 遍历当前node上的partial链表,找到page->freelist

    1. 这部分有些细节需要注意:

      1. 进行acquire_slab操作时第一次传入的object为空,mode为1
      2. 在mode为1的情况下,会将page->freelist设置为NULL
      3. acquire_slab的返回值后续会赋值给到object并返回,即第二次进入acquire时mode为0;
      4. 第二次及以后会将page挂到cpu->partial上,直到数量达到一半;
  2. 将当前的page赋值给到kmem_cache_cpu->page上

  3. 跳出去后进行几个判断,然后load_freelist操作

    1. kmem_cache_debug:默认是没有配置debug flag的,所以这里是OK的;
    2. pfmemalloc_match(page, gfpflags):这里是判断watermark标志是否存在,根据flag判断这里是返回true;

    即上述两个判断都满足后进行load_freelist操作,更新CPU结构上的freelist指针;

static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,struct kmem_cache_cpu *c, gfp_t flags)
{struct page *page, *page2;void *object = NULL;//注意这里object为NULLint available = 0;int objects;...spin_lock(&n->list_lock);list_for_each_entry_safe(page, page2, &n->partial, lru) {void *t;...//第一次进入时object值为NULL,就是说mode为1t = acquire_slab(s, n, page, object == NULL, &objects);if (!t)//返回值为page->freelist,这里不为空,第二次进来会是空;break;available += objects;if (!object) {c->page = page;stat(s, ALLOC_FROM_PARTIAL);object = t;//第一次进入后将t赋值给到object,即此时object不为空,mode为0} else {put_cpu_partial(s, page, 0);//后续会将page挂到kmem_cache_cpu上stat(s, CPU_PARTIAL_NODE);}if (!kmem_cache_has_cpu_partial(s) || available > s->cpu_partial / 2) //直到数量满足1/2break;}spin_unlock(&n->list_lock);return object;
}
//acquire_slab
static inline void *acquire_slab(struct kmem_cache *s,struct kmem_cache_node *n, struct page *page,int mode, int *objects)
{void *freelist;unsigned long counters;struct page new;lockdep_assert_held(&n->list_lock);freelist = page->freelist;counters = page->counters;new.counters = counters;*objects = new.objects - new.inuse;if (mode) {//第一次进入new.inuse = page->objects;new.freelist = NULL;//此值后续会赋值给到page->freelist} else {new.freelist = freelist;//mode为0的情况,不需要将page->freelist设置为NULL}VM_BUG_ON(new.frozen);new.frozen = 1;if (!__cmpxchg_double_slab(s, page, freelist, counters, new.freelist, new.counters, "acquire_slab"))return NULL;remove_partial(n, page);WARN_ON(!freelist);return freelist;
}

2.4 分配slab page

本部分主要考虑object的分配逻辑,所以没有详细分析new_slab部分内容,这部分内容下一小节整理

Linux 内存管理之 SLUB分配器(3):Object分配逻辑相关推荐

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

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

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

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

  3. linux内存管理(八)-不连续页分配和页表

    一.不连续页 1.不连续页的接口函数 a.用户台接口函数 //分配不连续的物理页并且把物理页映射到连续的虚拟地址空间: void *vmalloc(unsigned long size);//释放vm ...

  4. 深入理解Linux内存管理--目录导航

    日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 1 ...

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

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

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

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

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

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

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

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

  9. 深入理解Linux内存管理

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

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

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

最新文章

  1. MVP模式在Android中的应用之图片展示选择功能的框架设计
  2. 个人作业——福大微信公众号使用评测
  3. c语言输入输出重定向到串口,关于printf重定向到串口的问题分析 - 全文
  4. System.Web.HttpException: 无法验证数据解决办法
  5. 关于模糊查询时的索引问题.(了解一下,对提高代码效率非常有好处)
  6. Git Diff 魔法
  7. 谭浩强c语言程序设计 在线,C语言程序设计_谭浩强.pdf
  8. mysql修改表只读属性_VF设置的疑问
  9. sift算法matlab详解,sift算法原理详解及应用
  10. 五种压缩软件(WinRAR、7Z、好压、快压和360压缩)之比拼
  11. 思科模拟器去除登陆界面
  12. 网易免费/付费163企业邮smtp服务器地址
  13. 三步搞定ABAP DOI操作EXCEL
  14. POJ 3278,抓牛问题(BFS)
  15. 我们将与操作系统工作谈一场无私的爱──《云情人》思考
  16. jsp中的消息框:,警告框、确认框、提示框。
  17. 我爱Java系列---【分页查询】
  18. JAVA时间类型:Date、Calendar、LocalDate 、LocalTime、LocalDateTime、Instant的使用
  19. mysql怎么创建和调用out参数的存储过程
  20. Java学习——Java基础

热门文章

  1. 如何用adb链接手机,并异常情况下的处理(转)
  2. python--几种标准输出(stdout)重定向方式
  3. opencv_python学习笔记十三
  4. [ACM训练] 算法初级 之 搜索算法 之 广度优先算法BFS (POJ 3278+1426+3126+3087+3414)
  5. myeclipse激活+Aptana安装配置
  6. C++仿函数和typename的用法
  7. go语言渐入佳境[10]-function
  8. 2014中国高校SAS数据分析大赛拉开帷幕
  9. Java 异常类层次结构
  10. 如何判断sql server 2000 是否大了sp4补丁