Welcome 微信登录

首页 / 操作系统 / Linux / Linux内存管理之slab机制(初始化)

一、内核启动早期初始化 start_kernel()->mm_init()->kmem_cache_init()执行流程:1,初始化静态initkmem_list3三链;2,初始化cache_cache的nodelists字段为1中的三链;3,根据内存情况初始化每个slab占用的页面数变量slab_break_gfp_order;4,将cache_cache加入cache_chain链表中,初始化cache_cache;5,创建kmalloc所用的general cache:1)cache的名称和大小存放在两个数据结构对应的数组中,对应大小的cache可以从size数组中找到;2)先创建INDEX_AC和INDEX_L3下标的cache;3)循环创建size数组中各个大小的cache;6,替换静态本地cache全局变量:1) 替换cache_cache中的arry_cache,本来指向静态变量initarray_cache.cache;2) 替换malloc_sizes[INDEX_AC].cs_cachep的local cache,原本指向静态变量initarray_generic.cache;7,替换静态三链1)替换cache_cache三链,原本指向静态变量initkmem_list3;2)替换malloc_sizes[INDEX_AC].cs_cachep三链,原本指向静态变量initkmem_list3;8,更新初始化进度
  1. /* 
  2.  * Initialisation.  Called after the page allocator have been initialised and 
  3.  * before smp_init(). 
  4.  */  
  5. void __init kmem_cache_init(void)  
  6. {  
  7.     size_t left_over;  
  8.     struct cache_sizes *sizes;  
  9.     struct cache_names *names;  
  10.     int i;  
  11.     int order;  
  12.     int node;  
  13.     /* 在slab初始化好之前,无法通过kmalloc分配初始化过程中必要的一些对象 
  14.     ,只能使用静态的全局变量 
  15.     ,待slab初始化后期,再使用kmalloc动态分配的对象替换全局变量 */  
  16.   
  17.     /* 如前所述,先借用全局变量initkmem_list3表示的slab三链 
  18.     ,每个内存节点对应一组slab三链。initkmem_list3是个slab三链数组,对于每个内存节点,包含三组 
  19.     :struct kmem_cache的slab三链、struct arraycache_init的slab 三链、struct kmem_list3的slab三链 
  20.     。这里循环初始化所有内存节点的所有slab三链 */  
  21.     if (num_possible_nodes() == 1)  
  22.         use_alien_caches = 0;  
  23.     /*初始化所有node的所有slab中的三个链表*/  
  24.     for (i = 0; i < NUM_INIT_LISTS; i++) {  
  25.         kmem_list3_init(&initkmem_list3[i]);  
  26.         /* 全局变量cache_cache指向的slab cache包含所有struct kmem_cache对象,不包含cache_cache本身 
  27.         。这里初始化所有内存节点的struct kmem_cache的slab三链为空。*/  
  28.         if (i < MAX_NUMNODES)  
  29.             cache_cache.nodelists[i] = NULL;  
  30.     }  
  31.     /* 设置struct kmem_cache的slab三链指向initkmem_list3中的一组slab三链, 
  32.     CACHE_CACHE为cache在内核cache链表中的索引, 
  33.     struct kmem_cache对应的cache是内核中创建的第一个cache 
  34.     ,故CACHE_CACHE为0 */  
  35.     set_up_list3s(&cache_cache, CACHE_CACHE);  
  36.   
  37.     /* 
  38.      * Fragmentation resistance on low memory - only use bigger 
  39.      * page orders on machines with more than 32MB of memory. 
  40.      */  
  41.      /* 全局变量slab_break_gfp_order为每个slab最多占用几个页面 
  42.      ,用来抑制碎片,比如大小为3360的对象 
  43.      ,如果其slab只占一个页面,碎片为736 
  44.      ,slab占用两个页面,则碎片大小也翻倍 
  45.      。只有当对象很大 
  46.      ,以至于slab中连一个对象都放不下时 
  47.      ,才可以超过这个值 
  48.      。有两个可能的取值 
  49.      :当可用内存大于32MB时 
  50.      ,BREAK_GFP_ORDER_HI为1 
  51.      ,即每个slab最多占用2个页面 
  52.      ,只有当对象大小大于8192时 
  53.      ,才可以突破slab_break_gfp_order的限制 
  54.      。小于等于32MB时BREAK_GFP_ORDER_LO为0。*/  
  55.     if (totalram_pages > (32 << 20) >> PAGE_SHIFT)  
  56.         slab_break_gfp_order = BREAK_GFP_ORDER_HI;  
  57.   
  58.     /* Bootstrap is tricky, because several objects are allocated 
  59.      * from caches that do not exist yet: 
  60.      * 1) initialize the cache_cache cache: it contains the struct 
  61.      *    kmem_cache structures of all caches, except cache_cache itself: 
  62.      *    cache_cache is statically allocated. 
  63.      *    Initially an __init data area is used for the head array and the 
  64.      *    kmem_list3 structures, it"s replaced with a kmalloc allocated 
  65.      *    array at the end of the bootstrap. 
  66.      * 2) Create the first kmalloc cache. 
  67.      *    The struct kmem_cache for the new cache is allocated normally. 
  68.      *    An __init data area is used for the head array. 
  69.      * 3) Create the remaining kmalloc caches, with minimally sized 
  70.      *    head arrays. 
  71.      * 4) Replace the __init data head arrays for cache_cache and the first 
  72.      *    kmalloc cache with kmalloc allocated arrays. 
  73.      * 5) Replace the __init data for kmem_list3 for cache_cache and 
  74.      *    the other cache"s with kmalloc allocated memory. 
  75.      * 6) Resize the head arrays of the kmalloc caches to their final sizes. 
  76.      */  
  77.   
  78.     node = numa_node_id();  
  79.   
  80.     /* 1) create the cache_cache */  
  81.     /* 第一步,创建struct kmem_cache所在的cache,由全局变量cache_cache指向 
  82.     ,这里只是初始化数据结构 
  83.     ,并未真正创建这些对象,要待分配时才创建。*/  
  84.     /* 全局变量cache_chain是内核slab cache链表的表头 */  
  85.     INIT_LIST_HEAD(&cache_chain);  
  86.       
  87.     /* 将cache_cache加入到slab cache链表 */  
  88.     list_add(&cache_cache.next, &cache_chain);  
  89.   
  90.     /* 设置cache着色基本单位为cache line的大小:32字节 */  
  91.     cache_cache.colour_off = cache_line_size();  
  92.     /*  初始化cache_cache的local cache,同样这里也不能使用kmalloc 
  93.     ,需要使用静态分配的全局变量initarray_cache */  
  94.     cache_cache.array[smp_processor_id()] = &initarray_cache.cache;  
  95.     /* 初始化slab链表 ,用全局变量*/  
  96.     cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node];  
  97.   
  98.     /* 
  99.      * struct kmem_cache size depends on nr_node_ids, which 
  100.      * can be less than MAX_NUMNODES. 
  101.      */  
  102.      /* buffer_size保存slab中对象的大小,这里是计算struct kmem_cache的大小 
  103.      , nodelists是最后一个成员 
  104.      ,nr_node_ids保存内存节点个数,UMA为1 
  105.      ,所以nodelists偏移加上1个struct kmem_list3 的大小即为struct kmem_cache的大小 */  
  106.     cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +  
  107.                  nr_node_ids * sizeofstruct kmem_list3 *);  
  108. #if DEBUG   
  109.     cache_cache.obj_size = cache_cache.buffer_size;  
  110. #endif   
  111.     /* 将对象大小与cache line大小对齐 */  
  112.     cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,  
  113.                     cache_line_size());  
  114.     /* 计算对象大小的倒数,用于计算对象在slab中的索引 */  
  115.     cache_cache.reciprocal_buffer_size =  
  116.         reciprocal_value(cache_cache.buffer_size);  
  117.   
  118.     for (order = 0; order < MAX_ORDER; order++) {  
  119.         /* 计算cache_cache中的对象数目 */  
  120.         cache_estimate(order, cache_cache.buffer_size,  
  121.             cache_line_size(), 0, &left_over, &cache_cache.num);  
  122.         /* num不为0意味着创建struct kmem_cache对象成功,退出 */  
  123.         if (cache_cache.num)  
  124.             break;  
  125.     }  
  126.     BUG_ON(!cache_cache.num);  
  127.      /* gfporder表示本slab包含2^gfporder个页面 */  
  128.     cache_cache.gfporder = order;  
  129.       /* 着色区的大小,以colour_off为单位 */  
  130.     cache_cache.colour = left_over / cache_cache.colour_off;  
  131.     /* slab管理对象的大小 */  
  132.     cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +  
  133.                       sizeofstruct slab), cache_line_size());  
  134.   
  135.     /* 2+3) create the kmalloc caches */  
  136.     /* 第二步,创建kmalloc所用的general cache 
  137.     ,kmalloc所用的对象按大小分级 
  138.     ,malloc_sizes保存大小,cache_names保存cache名 */  
  139.     sizes = malloc_sizes;  
  140.     names = cache_names;  
  141.   
  142.     /* 
  143.      * Initialize the caches that provide memory for the array cache and the 
  144.      * kmem_list3 structures first.  Without this, further allocations will 
  145.      * bug. 
  146.      */  
  147.     /* 首先创建struct array_cache和struct kmem_list3所用的general cache 
  148.     ,它们是后续初始化动作的基础 */  
  149.     /* INDEX_AC是计算local cache所用的struct arraycache_init对象在kmalloc size中的索引 
  150.     ,即属于哪一级别大小的general cache 
  151.     ,创建此大小级别的cache为local cache所用 */  
  152.     sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,  
  153.                     sizes[INDEX_AC].cs_size,  
  154.                     ARCH_KMALLOC_MINALIGN,  
  155.                     ARCH_KMALLOC_FLAGS|SLAB_PANIC,  
  156.                     NULL);  
  157.     /* 如果struct kmem_list3和struct arraycache_init对应的kmalloc size索引不同 
  158.     ,即大小属于不同的级别 
  159.     ,则创建struct kmem_list3所用的cache,否则共用一个cache */  
  160.     if (INDEX_AC != INDEX_L3) {  
  161.         sizes[INDEX_L3].cs_cachep =  
  162.             kmem_cache_create(names[INDEX_L3].name,  
  163.                 sizes[INDEX_L3].cs_size,  
  164.                 ARCH_KMALLOC_MINALIGN,  
  165.                 ARCH_KMALLOC_FLAGS|SLAB_PANIC,  
  166.                 NULL);  
  167.     }  
  168.     /* 创建完上述两个general cache后,slab early init阶段结束,在此之前 
  169.     ,不允许创建外置式slab */  
  170.     slab_early_init = 0;  
  171.   
  172.     /* 循环创建kmalloc各级别的general cache */  
  173.     while (sizes->cs_size != ULONG_MAX) {  
  174.         /* 
  175.          * For performance, all the general caches are L1 aligned. 
  176.          * This should be particularly beneficial on SMP boxes, as it 
  177.          * eliminates "false sharing". 
  178.          * Note for systems short on memory removing the alignment will 
  179.          * allow tighter packing of the smaller caches. 
  180.          */  
  181.          /* 某级别的kmalloc cache还未创建,创建之,struct kmem_list3和 
  182.          struct arraycache_init对应的cache已经创建过了 */  
  183.         if (!sizes->cs_cachep) {  
  184.             sizes->cs_cachep = kmem_cache_create(names->name,  
  185.                     sizes->cs_size,  
  186.                     ARCH_KMALLOC_MINALIGN,  
  187.                     ARCH_KMALLOC_FLAGS|SLAB_PANIC,  
  188.                     NULL);  
  189.         }  
  190. #ifdef CONFIG_ZONE_DMA   
  191.         sizes->cs_dmacachep = kmem_cache_create(  
  192.                     names->name_dma,  
  193.                     sizes->cs_size,  
  194.                     ARCH_KMALLOC_MINALIGN,  
  195.                     ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|  
  196.                         SLAB_PANIC,  
  197.                     NULL);  
  198. #endif   
  199.         sizes++;  
  200.         names++;  
  201.     }  
  202.     /* 至此,kmalloc general cache已经创建完毕,可以拿来使用了 */  
  203.     /* 4) Replace the bootstrap head arrays */  
  204.     /* 第四步,用kmalloc对象替换静态分配的全局变量 
  205.     。到目前为止一共使用了两个全局local cache 
  206.     ,一个是cache_cache的local cache指向initarray_cache.cache 
  207.     ,另一个是malloc_sizes[INDEX_AC].cs_cachep的local cache指向initarray_generic.cache 
  208.     ,参见setup_cpu_cache函数。这里替换它们。*/  
  209.     {  
  210.         struct array_cache *ptr;  
  211.         /* 申请cache_cache所用local cache的空间 */  
  212.         ptr = kmalloc(sizeofstruct arraycache_init), GFP_NOWAIT);  
  213.   
  214.         BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);  
  215.         /* 复制原cache_cache的local cache,即initarray_cache,到新的位置 */  
  216.         memcpy(ptr, cpu_cache_get(&cache_cache),  
  217.                sizeofstruct arraycache_init));  
  218.         /* 
  219.          * Do not assume that spinlocks can be initialized via memcpy: 
  220.          */  
  221.         spin_lock_init(&ptr->lock);  
  222.         /* cache_cache的local cache指向新的位置 */  
  223.         cache_cache.array[smp_processor_id()] = ptr;  
  224.         /* 申请malloc_sizes[INDEX_AC].cs_cachep所用local cache的空间 */  
  225.         ptr = kmalloc(sizeofstruct arraycache_init), GFP_NOWAIT);  
  226.   
  227.         BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep)  
  228.                != &initarray_generic.cache);  
  229.         /* 复制原local cache到新分配的位置,注意此时local cache的大小是固定的 */  
  230.         memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep),  
  231.                sizeofstruct arraycache_init));  
  232.         /* 
  233.          * Do not assume that spinlocks can be initialized via memcpy: 
  234.          */  
  235.         spin_lock_init(&ptr->lock);  
  236.   
  237.         malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =  
  238.             ptr;  
  239.     }  
  240.     /* 5) Replace the bootstrap kmem_list3"s */  
  241.     /* 第五步,与第四步类似,用kmalloc的空间替换静态分配的slab三链 */  
  242.     {  
  243.         int nid;  
  244.       /* UMA只有一个节点 */  
  245.         for_each_online_node(nid) {  
  246.             /* 复制struct kmem_cache的slab三链 */  
  247.             init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid);  
  248.             /* 复制struct arraycache_init的slab三链 */  
  249.             init_list(malloc_sizes[INDEX_AC].cs_cachep,  
  250.                   &initkmem_list3[SIZE_AC + nid], nid);  
  251.             /* 复制struct kmem_list3的slab三链 */  
  252.             if (INDEX_AC != INDEX_L3) {  
  253.                 init_list(malloc_sizes[INDEX_L3].cs_cachep,  
  254.                       &initkmem_list3[SIZE_L3 + nid], nid);  
  255.             }  
  256.         }  
  257.     }  
  258.     /* 更新slab系统初始化进度 */  
  259.     g_cpucache_up = EARLY;  
  260. }  
  • 1
  • 2
  • 3
  • 4
  • 下一页
CentOS Oprofile 安装过程的几个错误注意点Linux内存管理之slab机制(创建slab)相关资讯      Linux内存 
  • Linux内存管理精述  (01月18日)
  • 在 Linux x86-32 模式下分析内存映  (02/08/2015 07:25:25)
  • Linux下如何释放cache内存  (02/02/2015 13:36:34)
  • 在 Linux x86-64 模式下分析内存映  (02/08/2015 07:33:09)
  • Linux系统入门学习:如何检查Linux  (02/06/2015 10:36:00)
  • Linux内存映射  (04/04/2014 13:21:48)
本文评论 查看全部评论 (0)
表情: 姓名: 字数