1. 分析的linux内核源码版本为4.18.0

2. 与slub相关的内核配置项为CONFIG_SLUB

3. 一切都从一个结构体数组kmalloc_caches开始,它的原型如下:

struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + ] __ro_after_init;

  3.1 这个数组定义在mm/slab_common.c中

  3.2 KMALLOC_SHIFT_HIGH是如何定义的呢? 

#define KMALLOC_SHIFT_HIGH  (PAGE_SHIFT + 1)
#define PAGE_SHIFT  12 (各个架构下的定义都有些差异,如果是arm64,那么是通过CONFIG_ARM64_PAGE_SHIFT来指定的,这个配置项在arch/arm64/Kconfig文件中定义,默认为12,也就是默认页面大小为4KiB,笔者以arm64为例)

    那么KMALLOC_SHIFT_HIGH=PAGE_SHIFT + 1 = 12 + 1 = 13,KMALLOC_SHIFT_HIGH+1=13+ 1= 14说明kmalloc_caches数组中有14个元素,每个元素是kmem_cache这个结构体

  3.3 分析一下sturct kmem_cache这个结构体

     

  /*
* Slab cache management.
*/
struct kmem_cache {
struct kmem_cache_cpu __percpu *cpu_slab;
/* Used for retriving partial slabs etc */
slab_flags_t flags;
unsigned long min_partial;
unsigned int size; /* The size of an object including meta data */
unsigned int object_size;/* The size of an object without meta data */
unsigned int offset; /* Free pointer offset. */
#ifdef CONFIG_SLUB_CPU_PARTIAL
/* Number of per cpu partial objects to keep around */
unsigned int cpu_partial;
#endif
struct kmem_cache_order_objects oo; /* Allocation and freeing of slabs */
struct kmem_cache_order_objects max;
struct kmem_cache_order_objects min;
gfp_t allocflags; /* gfp flags to use on each alloc */
int refcount; /* Refcount for slab cache destroy */
void (*ctor)(void *);
unsigned int inuse; /* Offset to metadata */
unsigned int align; /* Alignment */
unsigned int red_left_pad; /* Left redzone padding size */
const char *name; /* Name (only for display!) */
struct list_head list; /* List of slab caches */
#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
struct work_struct kobj_remove_work;
#endif
#ifdef CONFIG_MEMCG
struct memcg_cache_params memcg_params;
/* for propagation, maximum size of a stored attr */
unsigned int max_attr_size;
#ifdef CONFIG_SYSFS
struct kset *memcg_kset;
#endif
#endif #ifdef CONFIG_SLAB_FREELIST_HARDENED
unsigned long random;
#endif #ifdef CONFIG_NUMA
/*
* Defragmentation by allocating from a remote node.
*/
unsigned int remote_node_defrag_ratio;
#endif #ifdef CONFIG_SLAB_FREELIST_RANDOM
unsigned int *random_seq;
#endif #ifdef CONFIG_KASAN
struct kasan_cache kasan_info;
#endif unsigned int useroffset; /* Usercopy region offset */
unsigned int usersize; /* Usercopy region size */ struct kmem_cache_node *node[MAX_NUMNODES];
};

  3.4 struct kmem_cache中有哪些域是需要关注到的呢?

    3.4.1 node

      struct kmem_cache_node *node[MAX_NUMNODES]; 

      这里面MAX_NUMNODES定义如下:

    

      #define MAX_NUMNODES    (1 << NODES_SHIFT)

      那么NODES_SHIFT又是如何定义的呢?

    

      #ifdef CONFIG_NODES_SHIFT
      #define NODES_SHIFT CONFIG_NODES_SHIFT
      #else
      #define NODES_SHIFT 0
      #endif

      如果定义了CONFIG_NODES_SHIFT,那么NODES_SHIFT就等于CONFIG_NODES_SHIFT的值;

      如果未定义CONFIG_NODES_SHIFT,那么NODES_SHIFT就等于0;

      假设未定义CONFIG_NODES_SHIFT,那么MAX_NUMNODES就等于1,也就是只有一个kmem_cache_node节点.

    3.4.2 cpu_slab

      

      struct kmem_cache_cpu __percpu *cpu_slab;

      表示每个cpu都具有一个这个的结构来描述当前slab的情况

      

      __percpu是什么?

      

      # define __percpu   __attribute__((noderef, address_space()))

      __percpu表示一种特性,是用来修饰变量的.noderef指定这个变量必须是有效的,address_space(3)则指定变量所在的地址空间为3,也就是cpu空间.作用就是保证每个cpu都有这个变量的副本

    3.4.3 size

      

      unsigned int size;  /* The size of an object including meta data */

      表示包含元数据的一个object的大小

    3.4.4 object_size

      

      unsigned int object_size;/* The size of an object without meta data */

      表示不包含元数据的一个object的大小

    3.4.5 offset

      
      unsigned int offset;    /* Free pointer offset. */

      表示空闲指针的偏移量

  3.5 __ro_after_init是什么东西?      

    #define __ro_after_init __attribute__((__section__(".data..ro_after_init")))

    这是一个宏,定义在include/linux/cache.h中,被用来标记初始化之后只读的内容

    这里面涉及到一个段.data..ro_after_init,可以在include/asm-generic/vmlinux.lds.h中找到   

            #ifndef RO_AFTER_INIT_DATA
    #define RO_AFTER_INIT_DATA \
    __start_ro_after_init = .; \
    *(.data..ro_after_init) \
    __end_ro_after_init = .;
    #endif    

4.  如何填充kmalloc_caches数组的呢?

  start_kernel()-> (init/main.c)

      mm_init()->  (init/main.c)

        kmem_cache_init()->  (mm/slub.c)

          create_kmalloc_caches()-> (mm/slab_common.c)

            new_kamalloc_cache()-> (mm/slab_common.c)

              create_kmalloc_cache()-> (mm/slab_common.c)

  从源码中可以得知kmalloc_caches数组由create_kmalloc_cache()填充每一个数组中的元素

5. slub中支持的object的大小范围是多少?

  每个kmalloc_caches中的元素会使用结构体kmem_cache中的域size和objsize来指定slab中每个object的大小,object的大小从全局常量结构体数组kmalloc_info中获取

  const struct kmalloc_info_struct kmalloc_info[] __initconst = {
{NULL, }, {"kmalloc-96", },
{"kmalloc-192", }, {"kmalloc-8", },
{"kmalloc-16", }, {"kmalloc-32", },
{"kmalloc-64", }, {"kmalloc-128", },
{"kmalloc-256", }, {"kmalloc-512", },
{"kmalloc-1024", }, {"kmalloc-2048", },
{"kmalloc-4096", }, {"kmalloc-8192", },
{"kmalloc-16384", }, {"kmalloc-32768", },
{"kmalloc-65536", }, {"kmalloc-131072", },
{"kmalloc-262144", }, {"kmalloc-524288", },
{"kmalloc-1048576", }, {"kmalloc-2097152", },
{"kmalloc-4194304", }, {"kmalloc-8388608", },
{"kmalloc-16777216", }, {"kmalloc-33554432", },
{"kmalloc-67108864", }
};

  从数组中的最后一个元素可以获知支持的最大object的大小为2^26=64MiB,但是从以下代码分析:

  void __init create_kmalloc_caches(slab_flags_t flags)
{
int i; for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) {
if (!kmalloc_caches[i])
new_kmalloc_cache(i, flags);

  可得:

    kmalloc_caches数组中仅下标为KMALLOC_SHIFT_LOW到KMALLOC_SHIFT_HIGH的元素才被初始化,

    也就是从3->13支持的最小object大小为2^3=8字节,最大object大小为2^13=8KiB,说明kmalloc_caches数组的前三个元素并没有被初始化,仅初始化数组的后面11个元素.

    从以上分析可得slub支持的最大object的大小为页面大小的两倍(PAGE_SIZE*2),页面大小为4KiB,那么最大object的大小为4KiB * 2 = 8KiB

                  

 

分析linux内核中的slub内存管理算法的更多相关文章

  1. Linux内核中常用的数据结构和算法(转)

    知乎链接:https://zhuanlan.zhihu.com/p/58087261 Linux内核代码中广泛使用了数据结构和算法,其中最常用的两个是链表和红黑树. 链表 Linux内核代码大量使用了 ...

  2. linux内核中的C语言常规算法(前提:你的编译器要支持typeof和type)

    学过C语言的伙伴都知道,曾经比较两个数,输出最大或最小的一个,或者是比较三个数,输出最大或者最小的那个,又或是两个数交换,又或是绝对值等等,其实这些算法在linux内核中通通都有实现,以下的代码是我从 ...

  3. Linux内核入门到放弃-内存管理-《深入Linux内核架构》笔记

    概述 内存管理的实现涵盖了许多领域: 内存中的物理内存页管理 分配大块内存的伙伴系统 分配较小内存块的slab.slub和slob分配器 分配非连续内存块的vmalloc机制 进程的地址空间 在IA- ...

  4. Linux内核设计笔记12——内存管理

    内存管理学习笔记 页 页是内核管理内存的基本单位,内存管理单元(MMU,管理内存并把虚拟地址转化为物理地址的硬件)通常以页为单位进行处理,从虚拟内存的角度看,页就是最小单位. struct page{ ...

  5. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  6. linux内核(四)内存管理单元MMU

    1,基本概念 一个程序运行时没必要全部都同时装入内存,只需要把当前需要运行的部分装入内存即可,这样就使得一个大程序可以在较小的内存中运行,也使得内存中可以同时装入更多的程序并发执行,从用户角度看,该系 ...

  7. Linux内核中的有关Page的算法

    static inline int get_order(unsigned long size) { int order; size = (size-1) >> (PAGE_SHIFT-1) ...

  8. Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制

    Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches   Slab内存管理机制 SLUB内存管理机制 http://w ...

  9. Linux内核中的GPIO系统之(3):pin controller driver代码分析

    一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...

随机推荐

  1. 新购买的vps应该做的几件事情

    1. 修改root密码      passwd   root 2.新建用户     useradd  vinentguo 3.配置免密码登陆 .使用新建用户登陆vps. mkdir ~/.ssh/ch ...

  2. 网站优化不等于搜索引擎优化SEO

    对于SEO相信搞网络营销的人基本上都知道这个名词,英文全称为search engine optimization,中文一般叫搜索引擎优化,也有的叫搜索引擎定位(Search Engine Positi ...

  3. 完美解决onchange不能实时的监听

    我们大家都知道onchange有时候很不好用,因为onchange事件是离开焦点后才会被触发,而不是实时去监听! 那么oninput()事件和onpropertychange()完美的解决了问题:(o ...

  4. 洛谷P1967 货车运输 [noip2013] 图论

    正解:kruskal+LCA 解题报告: 哇真实心痛了...明明都没多少时间了我居然耗了一个上午+一个中午在上面?哭死辽我QAQ果然菜是原罪QAQ 然后这题,我先港下60pts做法趴?话说其实我觉得我 ...

  5. 【HTML5】初识HTML5

    HTML5 简介 HTML5是HTML最新的修订版本,2014年10月由万维网联盟(W3C)完成标准制定. HTML5的设计目的是为了在移动设备上支持多媒体. HTML5 简单易学. HTML5 是下 ...

  6. idong常用js总结

    1.判断屏幕高度 $(document).ready(function() {    $("#left").height($(window).height());    $(&qu ...

  7. 看懂Oracle执行计划、表连接方式

    看懂Oracle执行计划  原文:https://www.cnblogs.com/Dreamer-1/p/6076440.html 最近一直在跟Oracle打交道,从最初的一脸懵逼到现在的略有所知,也 ...

  8. 2.深度学习中的batch_size的理解

    Batch_Size(批尺寸)是机器学习中一个重要参数,涉及诸多矛盾,下面逐一展开. 首先,为什么需要有 Batch_Size 这个参数? Batch 的选择,首先决定的是下降的方向.如果数据集比较小 ...

  9. 发现《深入理解C++11》中扩展的friend代码的错误

    目前在总结现代C++的新特性,看了<深入理解C++11>这本书. 今天看到扩展的friend语法这一节,遇到了问题.本节电子版内容参见:https://book.2cto.com/2013 ...

  10. python 循环队列的实现

    最近在做一个东西的时候发现需要用到循环队列,实现先进先出(FIFO),不断往里面添加数据,当达到某个限定值时,最先进去的出去,然后再添加.之后需要对队列里面的内容进行一个筛选,作其他处理.首先我想到了 ...