zoukankan      html  css  js  c++  java
  • 分析linux内核中的slub内存管理算法

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

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

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

    struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1] __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(3)))

          __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中找到   

    1            #ifndef RO_AFTER_INIT_DATA
    2     #define RO_AFTER_INIT_DATA  
    3     __start_ro_after_init = .;  
    4     *(.data..ro_after_init) 
    5     __end_ro_after_init = .;
    6     #endif        
    View Code

    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,                      0},     {"kmalloc-96",             96},
          {"kmalloc-192",           192},     {"kmalloc-8",               8},
          {"kmalloc-16",             16},     {"kmalloc-32",             32},
          {"kmalloc-64",             64},     {"kmalloc-128",           128},
          {"kmalloc-256",           256},     {"kmalloc-512",           512},
          {"kmalloc-1024",         1024},     {"kmalloc-2048",         2048},
          {"kmalloc-4096",         4096},     {"kmalloc-8192",         8192},
          {"kmalloc-16384",       16384},     {"kmalloc-32768",       32768},
          {"kmalloc-65536",       65536},     {"kmalloc-131072",     131072},
          {"kmalloc-262144",     262144},     {"kmalloc-524288",     524288},
          {"kmalloc-1048576",   1048576},     {"kmalloc-2097152",   2097152},
          {"kmalloc-4194304",   4194304},     {"kmalloc-8388608",   8388608},
          {"kmalloc-16777216", 16777216},     {"kmalloc-33554432", 33554432},
          {"kmalloc-67108864", 67108864}
      };
    View Code

      从数组中的最后一个元素可以获知支持的最大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

                      

     

  • 相关阅读:
    Operation Queue
    Dispatch Sources
    Base64编码详解
    属性存取、直接访问实例变量
    管理关联对象和NSDictionary区别
    3个Block替换Delegate的场景
    Objective-C消息机制
    Dispatch Queues调度队列
    DNS64/NAT64 Networks(解决IPv6审核被拒)
    NSObject的Initialize与Load方法
  • 原文地址:https://www.cnblogs.com/dakewei/p/10497544.html
Copyright © 2011-2022 走看看