slub分配流程-kmem_cache_alloc函数

static __always_inline void *slab_alloc_node(struct kmem_cache *s,gfp_t gfpflags, int node, unsigned long addr)
{void *object;struct kmem_cache_cpu *c;struct page *page;unsigned long tid;s = slab_pre_alloc_hook(s, gfpflags);if (!s)return NULL;
redo:/* * 保证获取到的tid和kmem_cache_cpu是同一个cpu上面的,以避免中间发生cpu切换* 一旦不匹配则在do循环中重新获取直到匹配为止;*/do {tid = this_cpu_read(s->cpu_slab->tid);c = raw_cpu_ptr(s->cpu_slab);} while (IS_ENABLED(CONFIG_PREEMPTION) &&unlikely(tid != READ_ONCE(c->tid)));barrier();object = c->freelist;page = c->page;/** 从这里判断进入slowpath还是fastpath* 进入fastpath的条件:* 1、page与当前节点node匹配* 2、c->freelist != NULL*/if (unlikely(!object || !node_match(page, node))) {object = __slab_alloc(s, gfpflags, node, addr, c);stat(s, ALLOC_SLOWPATH);/* 标记slowpath状态 */} else {void *next_object = get_freepointer_safe(s, object);if (unlikely(!this_cpu_cmpxchg_double(s->cpu_slab->freelist, s->cpu_slab->tid,object, tid,next_object, next_tid(tid)))) {note_cmpxchg_failure("slab_alloc", s, tid);goto redo;}prefetch_freepointer(s, next_object);stat(s, ALLOC_FASTPATH);/* 标记fastpath状态 */}maybe_wipe_obj_freeptr(s, object);if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object)memset(object, 0, s->object_size);slab_post_alloc_hook(s, gfpflags, 1, &object);return object;
}

从图中可以大致可以分成4种情况:

1、c->freelist != NULL;

2、c->freelist = NULL,c->partital != NULL;

3、c->partital = NULL,n->partital != NULL;

4、n->partital = NULL的情况;

第一种情况,c->freelist != NULL,即在本地的slab缓存池不为空,这种分配即fastpath操作,精简代码后如下所示:

void *next_object = get_freepointer_safe(s, object);      /*(1)*/
if (unlikely(!this_cpu_cmpxchg_double(                    /*(2)*/s->cpu_slab->freelist, s->cpu_slab->tid,object, tid,next_object, next_tid(tid)))) {note_cmpxchg_failure("slab_alloc", s, tid);goto redo;}
prefetch_freepointer(s, next_object);                     /*(3)*/
stat(s, ALLOC_FASTPATH);/* 标记fastpath状态 */
/* * (1)获取下一个空闲的object赋值给next_object* (2)原子操作,主要做了三件事:**重定向首指针指向当前CPU空间;**判断tid和freelist未被修改;**用新的tid和freelist覆盖旧的数据:s->cpu_slab->freelist = next_objects->cpu_slab->tid = next_tid(tid)此时c->freelist就指向了新的下一个空闲对象;* (3)刷新数据,主要是下一个空闲object的地址指向;*/

图解如下图所示:

其余的几种情况均属于slowpath,在__slab_alloc中执行,

当kmem_cache_cpu的freelist没有可用的object时,需要去kmem_cache_cpu的partital链表中寻找可用的object,如果c->partial存在,则可找到对应的object,对应的函数主体如下:

     if (slub_percpu_partial(c)) {page = c->page = slub_percpu_partial(c);/*(1)*/slub_set_percpu_partial(c, page);       /*(2)*/stat(s, CPU_PARTIAL_ALLOC); goto redo;                              /*(3)*/}/** (1)slub_percpu_partial(c)函数实际上是返回c->partial,赋值给c->page;* (2)更新c->partial的链表,将c->partial指向下一个page链表中的对象;实际上就是:c->partial = page->next;(3)返回redo标签,重新进行freelist的获取和更新;*/

图解如下图所示:

当kmem_cache_cpu的freelist和partital链表都没有可用的object的时候,就需要去kmem_cache_node中去寻找可用的object。主体函数为get_partial_node:

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;unsigned int available = 0;int objects;if (!n || !n->nr_partial)return NULL;spin_lock(&n->list_lock);list_for_each_entry_safe(page, page2, &n->partial, slab_list) {void *t;if (!pfmemalloc_match(page, flags))continue;/*(1)*/t = acquire_slab(s, n, page, object == NULL, &objects);if (!t)break;available += objects;if (!object) {c->page = page;stat(s, ALLOC_FROM_PARTIAL);object = t;} else {put_cpu_partial(s, page, 0);stat(s, CPU_PARTIAL_NODE);}/*(2)*/if (!kmem_cache_has_cpu_partial(s)|| available > slub_cpu_partial(s) / 2)break;}spin_unlock(&n->list_lock);return object;
}
/** (1)变量partial,acquire_slab获取partial链表上slab空闲的数量,对于第一个获取到的slab,挂到c->page上;* (2)然后将后续slab挂到c->partial,直到满足其数量大于cpu_partial的一半;*/

如果在kmem_cache_cpu的freelist、partital链表以及kmem_cache_node的partital链表中都没有可用的object时,则需要调用new_slab函数从伙伴系统重新申请一页内存,此时函数主体如下:

 page = new_slab(s, flags, node);     /*(1)*/if (page) {c = raw_cpu_ptr(s->cpu_slab);/*(2)*/if (c->page)                 /*(3)*/flush_slab(s, c);freelist = page->freelist;   /*(4)*/page->freelist = NULL;       /*(5)*/stat(s, ALLOC_SLAB);c->page = page;              /*(6)*/*pc = c;
}
/** (1)从伙伴系统以页为单位分配内存,保存在page中;* (2)获取当前cpu的kmem_cache_cpu结构;* (3)如果存在c->page,则说明当前cpu(暂不清楚)* (4)返回page中的freelist;* (5)将page中的freelist指向NULL;* (6)将新申请的page加入cpu本地缓存(c->page = page);其中(4)(5)(6)步主要是将申请的page       加入到该CPU的本地缓存中;*/

当调用new_slab失败,无法从伙伴系统获取内存时,说明系统内存不足,此时就会发生OOM;

slub分配流程-kmem_cache_alloc函数相关推荐

  1. Slub代码流程分析

    Slub代码流程分析: slub的代码晦涩难懂,在看书或者相关资料时看似简单,再去对照代码分析时会发现被打回原形,就像数学老师推导公式和自己去推导公式一样.因此,需要静下来心来仔细研读,看完原理之后分 ...

  2. 深入理解JVM之对象分配流程

    Java对象分配流程 栈上分配 参考: https://www.cnblogs.com/BlueStarWei/p/9358757.html (讲的很好) https://blog.csdn.net/ ...

  3. 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)

    [SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...

  4. socket编程流程及函数详解

    socket编程流程及函数详解-服务器端 一.创建socket 二.命名socket 2.1通用的socket地址结构体 2.2专用socket地址 三.监听socket 四.接受连接 五.总结 一. ...

  5. JVM-剖析对象内存分配流程

    文章目录 Pre 对象分配流程总览 流程分解 栈上分配对象 (逃逸分析) Eden区分配对象 -XX:+UseAdaptiveSizePolicy 默认开启 Eden区域分配对象Demo 大对象直接进 ...

  6. LTE(4G) GUTI分配流程

    目录 MME中的UE上下文 GUTI GUTI的组成 GUTI的主要作用 TA List COUNT SGW TEID eNB S1AP id eNB TEID GUTI重新分配 GUTI分配出现的异 ...

  7. java对象的内存分配流程

    了解对象的内存分配流程对常见内存溢出问题.jvm优化有很大作用. 内存分配原则 对象栈内分配 通常理解new对象都在堆中分配存储空间,但是当(通过逃逸分析 确定)对象仅在方法内使用而未被外部访问的时候 ...

  8. 编写一个函数,模拟微信发红包的红包分配过程。函数有两个参数:一个参数表示红包总金额,默认值为100,另一个参数表示红包数量,默认为10。程序输入:红包总金额和红包数量;程序输出:每个红包的金额。要求:

    题目 ‬‬编写一个函数,模拟微信发红包的红包分配过程.函数有两个参数:一个参数表示红包总金额,默认值为100,另一个参数表示红包数量,默认为10.程序输入:红包总金额和红包数量:程序输出:每个红包的金 ...

  9. linux内核网络协议栈--接收流程及函数(九)

    本章来看下,数据是如何从网络中接收并最后到达应用程序的. 网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息. 1.链路层 包到达机器的物理网卡时候触发一个中断,并将通过 ...

  10. 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )

    文章目录 一.进程注入原理 二.远程调用流程 ( 获取 so 动态库地址 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 ) 一.进程注入原理 调试进程 At ...

最新文章

  1. 更换用installshield打包生成exe文件的图标
  2. php生成文字闪烁,如何用jquery实现闪烁文字效果
  3. 3.2 指数型生成函数
  4. iphone备忘录突然没了_为什么用过iPhone的人都不再想换回安卓?网友:过于真实,哭了...
  5. 结合CmakeList来更好地理解windows下的动态库和静态库
  6. python 选择题 多线程_python多线程练习题
  7. matlab 模态,用matlab做模态分析
  8. SOLD2算法详解之1 backbone(CVPR2021 源码解析)
  9. webview无法播放视频
  10. 三大 Windows 文件搜索神器 Everything、Listary、AnyTXT Searcher 功能特色与区别详解
  11. SprintBoot:Post请求的参数多一个逗号的解决方法
  12. FAT16文件系统简介
  13. java excel单元格背景色_POI 设置Excel单元格背景色(setFillForegroundColor)
  14. db4o数据库的基本操作
  15. Pandas中的pivot操作
  16. htmlcss全屏视频背景
  17. 【项目管理】项目选择与项目章程
  18. [234] 回文链表
  19. SQL优化的魅力!从 30248s 到 0.001s
  20. python爬取笔趣阁小说的代码微小调整修改

热门文章

  1. 车牌识别LPR(八)-- 字符识别
  2. 在gfs2中关闭selinux
  3. [转]printf 函数实现的深入剖析
  4. 在电脑前,写点什么...
  5. 2018年视频云服务市场格局进入整合阶段,阿里云视频云位居市场竞争力领导者的位置... 1
  6. Python查看文章中每个单词的出现频率
  7. HTML5新标签-Video
  8. 阿里天池大赛实战记录之菜鸟-需求预测与分仓规划
  9. IPC$***--个人练习
  10. jQuery - animate(滑块滑动)