[内核内存] slab分配器1---slab机制详解

2023-11-16


linux中的伙伴系统内存分配器是以页为最小粒度来进行内存分配。在实际的应用中,内核存储的大多数obj(如strcut task_strcuct,struct inode等数据结构)往往只需要几字节到几百字节不等。如果这些内核object的内存申请和释放都通过伙伴系统进行管理,会有以下缺点:

  1. 内存资源浪费,页内部碎片化严重
  2. 内存分配效率低

比如内核用伙伴系统为一个128字节的obj分配内存,内核不得不分配一个4k的page来存储该object,该页剩余的3972字节将会被闲置,内存资源被浪费。而且伙伴系统在释放一个内存块后,会立即将该内存块放在对应的freelist上,且该内存块还有可能与freelist上的相邻内存块合并成高一阶的内存块,若此时内核马上又要使用该内存块,则还需要再次从伙伴系统的freelist上去申请对应内存块,这种操作效率是很低的(未合理使用cpu高速缓存)。

为解决上面小块内存分配时遇到的问题,linux内核提出了slab分配机制,该内存分配器不是按页进行内存分配,而是按字节来分配的。

1 slab分配器原理

slab分配器中用到了对象这个概念,所谓对象就是内核中的数据结构以及对该数据结构进行创建和撤销的操作。它的基本思想是将内核中经常使用的对象放到slab缓存中,并且由系统保持为初始的可利用状态。比如进程描述符,内核中会频繁对此数据进行申请和释放。当一个新进程创建时,内核会直接从slab分配器的slab缓存中获取一个已经初始化了的对象;当进程结束时,该结构所占的页框并不被释放,而是重新返回slab分配器中。如果没有基于对象的slab分配器,内核将花费更多的时间去分配、初始化以及释放一个对象。

slab分配器把对象分组放进slab缓存。每个slab缓存都是同种类型对象的一种“储备”。一个slab cache管理一组大小固定的内存块(也称为对象实体),每个内存块都可用作一种数据结构。slab cache中的内存块来自一到多个slab。一个slab来自物理内存管理器的一到多个物理页,该slab被分成一组固定大小的块,被称为slab对象(object),一个slab属于一个slab cache,其中的对象就是该slab cache所管理的固定大小的内存块。所以一个slab cache可以有一到多个slab。

在基于slab的内核内存管理器中,基本的概念是保存管理型数据的缓存(即slab cache)和保存被管理对象的各个slab。每个缓存都负责一种对象类型,比如kmalloc-128缓存负责管理65-128字节内存空间的的分配。系统中的所有缓存类型都保存在一个链表slab_caches中。下图给出了slab分配器的各个组成部分间的相互关系:

在这里插入图片描述

slab分配器有以下三个基本目标:

  1. 减少伙伴算法在分配小块连续内存时所产生的内部碎片;
  2. 将频繁使用的对象缓存起来,减少分配、初始化和释放对象的时间开销。
  3. 通过着色技术调整对象以更好的使用硬件高速缓存;

2 slab分配器重要数据结构以及组织关系

2.1 slab cache描述符struct kmem_cache

在slab分配器中slab cache的描述符为struct kmem_cache,它是该机制的核心数据结构。

在slab分配器中,最顶层结构为slab cache,其描述符为struct kmem_cache.linux中每个slab obj对应的slab cache都有自己的名字(如:ext4_inode_cache,kmalloc-8和kmalloc-16等).

struct kmem_cache用于描述一种slab cache,并管理着一个或多个该slab中的的所有obj。linux中所有的kmem_cache会保持在一个以slab_caches作为头节点的链表中。kmem_cache代码定义如下所示。

// mm_slab_def.h
/*
 * Definitions unique to the original Linux SLAB allocator.
 */

struct kmem_cache {
    //本地高速缓存,每CPU结构,对象释放时,优先放入这个本地CPU高速缓存中
	struct array_cache __percpu *cpu_cache;
/* 1) Cache tunables. Protected by slab_mutex */
    /*batchcount指定了在per-CPU变量中entry列表为空的情况下,从缓存的slab中获取对象的数目。它还表示在
     *缓存增长时,若entry数组中obj数量超过limit限制后,需要从entry数组中迁移走的obj数量(到本地节点cpu共享空闲链
     *表中)。
     */
	unsigned int batchcount;
    //本地高速缓存中entry数组中空闲obj的最大数目
	unsigned int limit;
    //CPU共享高速缓存标志,实际地址保存在kmem_cache_node结构中
	unsigned int shared;
	//对象长度 + 填充字节
	unsigned int size;
	struct reciprocal_value reciprocal_buffer_size;
/* 2) touched by every alloc & free from the backend */
	//属性的标识,如果SLAB管理结构放在外部,则CFLAGS_OFF_SLAB置1
	unsigned int flags;		/* constant flags */
    //每个slab中obj数量
	unsigned int num;		/* # of objs per slab */

/* 3) cache_grow/shrink */
	/* order of pgs per slab (2^n) */
    //每个slab页块的阶(一个slab由2^gfporder个页构成)
	unsigned int gfporder;

	/* force GFP flags, e.g. GFP_DMA */
    //从伙伴系统分配页,补足slab时,页分配的gfp码
	gfp_t allocflags;

	//一个slab中有多少不同的cache line
    size_t colour;			/* cache colouring range */
    //一个cache colour的长度,和一个cache line的大小相同
	unsigned int colour_off;	/* colour offset */
    /*
     *空闲对象链表放在slab外部时使用,管理用于slab对象管理结构中freelist成员的缓存,也就是又一个新缓存
     */
	struct kmem_cache *freelist_cache;
    //空闲对象链表的大小
	unsigned int freelist_size;

	/* constructor func */
    // 创建高速缓存时的构造函数指针,一半为null
	void (*ctor)(void *obj);

/* 4) cache creation/removal */
     //slab缓存名字
	const char *name;
    //slab缓存描述符双向链表指针
	struct list_head list;
	int refcount;
    //slab中每个obj的大小
	int object_size;
    //obj对齐字节
	int align;
...
...
...
	//slab节点链表组,对于NUMA系统中每个节点都会有一个struct kmem_cache_node数据结构
	struct kmem_cache_node *node[MAX_NUMNODES];
};

通过struct kmem_cache的代码实现可以看出,slab cache中所有slab的大小一致,由一个或多个连续页组成(通常为一个page,伙伴系统提供),每个slab中的obj大小和数量也是相同的。

slab cache描述符struct kmem_cache中除了相关的管理数据外,有两个很重要的成员:

  1. struct array_cache __percpu *cpu_cache:

    1. cpu_cache是一个Per-CPU数据结构,每个CPU独享(相当于函数和它局部变量的关系),用来表示本地CPU的slab cache对象缓冲池(注意是slab cache obj缓冲池不是slab cache slab缓冲池)。
    2. CPU都有自己的硬件高速缓存,当前CPU上释放对象时,这个对象很可能还在CPU的硬件高速缓存中,这时使用这个对象的代价是非常小的,不需要重新装载到硬件高速缓存中,离CPU又最近。同时还可以减少锁的竞争,尤其是在多个CPU同时申请同样size或者同个缓存对象时,无需加锁即可操作。
    3. array_cache中的entry空数组,就是用于保存本地cpu刚释放的obj,所以该数组初始化时为空,只有本地cpu释放slab cache的obj后才会将此obj装入到entry数组。array_cache的entry成员数组中保存的obj数量是由成员limit控制的,超过该限制后会将entry数组中的batchcount个obj迁移到对应节点cpu共享的空闲对象链表中。
    4. entry数组的访问机制是LIFO(last in fist out),此种设计非常巧妙,能保证本地cpu最近释放该slab cache的obj立马被下一个slab内存申请者获取到(有很大概率此obj仍然在本地cpu的硬件高速缓存中).
    // mm_slab_def.h
    /*
     * struct array_cache
     *
     * Purpose:
     * - LIFO ordering, to hand out cache-warm objects from _alloc
     * - reduce the number of linked list operations
     * - reduce spinlock operations
     *
     * The limit is stored in the per-cpu structure to reduce the data cache
     * footprint.
     *
     */
    struct array_cache {
        //当前CPU上该slab可用对象数量
    	unsigned int avail;
        //最大对象数目,和kmem_cache中一样
    	unsigned int limit;
        /*同kmem_cache,batchcount指定了在per-CPU列表为空的情况下,从缓存的slab中获取对象的数目。它还表示在
         *缓存增长时,若entry数组中obj数量超过limit限制后,需要迁移entry中obj的数量(到本地节点cpu共享空闲链
         *表中)。
         */
    	unsigned int batchcount;
    	/*在从缓存移除一个对象时,将touched设置为1,而缓存收缩时, 则将touched设置为0。这使得内核能够确认在缓
    	 * 存上一次收缩之后是否被访问过,也是缓存重要性的一个标志。
    	 */
        unsigned int touched;
        /*最后一个成员entry是一个伪数组, 其中并没有数组项, 只是为了便于访问内存中array_cache实例之后缓存中的
         *各个对象而已
         */
    	void *entry[];	/*
    			 * Must have this definition in here for the proper
    			 * alignment of array_cache. Also simplifies accessing
    			 * the entries.
    			 */
    };
    
  2. struct kmem_cache_node *node[MAX_NUMNODES]:

    1. slab缓存会为不同的节点维护一个自己的slab链表,用来缓存和管理自己节点的slab obj,这通过kmem_cache中node数组成员来实现,node数组中的每个数组项都为其对应的节点分配了一个struct kmem_cache_node结构来。

    2. struct kmem_cache_node结构定义的变量是一个每node变量。相比于struct array_cache定义的每cpu变量,kmem_cache_node管理的内存区域粒度更大,因为kmem_cache_node维护的对象是slab,而array_cache维护的对象是slab中的obj(一个kmem_cache可能包含一个或多个slab,而一个slab中可能包含一个或多个slab obj).

    3. 通过下面struct kmem_cache_node结构的代码实现我们来分析该结构体如何实现对本地节点指定slab cache中所有的slab进行管理的。

      //mm/slab.h
      struct kmem_cache_node {
          //该链表中存储的所有slab中只有部分obj是空闲的
      	struct list_head slabs_partial;	/* partial list first, better asm code */
          //该链表中存储的所有slab中不存在空闲的obj
      	struct list_head slabs_full;
          //该链表中存储的所有slab中每个obj都是空闲的
      	struct list_head slabs_free;
          //该节点中此kmem_cache的slab总数
      	unsigned long num_slabs;
          //该节点中此kmem_cache空闲obj总数
      	unsigned long free_objects;
          //该节点中此kmem_cache中空闲obj数量的上限,多了就会回收到伙伴系统的空闲链表中
      	unsigned int free_limit;
      	unsigned int colour_next;	/* Per-node cache coloring */
          //该节点上所有cpu共享的本地高速缓存
      	struct array_cache *shared;	/* shared per node */
          //其他节点上所有cpu共享的本地高速缓存
      	struct alien_cache **alien;	/* on other nodes */
      	unsigned long next_reap;	/* updated without locking */
      	int free_touched;		/* updated without locking */
      };
      

      由上代码可以看出,struct kmem_cache_node对于本节点中slab的管理主要分了3个链表:slabs_partial(部分空闲slab链表),非空闲slab链表(slabs_full)和全空闲slab链表(slabs_free).struct kmem_cache_node还会将本地节点中需要节点共享的slab obj缓存在它的shared成员中。若本地节点向访问其他节点贡献的slab obj,可以利用struct kmem_cache_node中的alien成员去获取。

2.2 slab描述符struct page

为了提高linux内存利用率,slab描述符结合在页描述符struct page中,当页描述符成员flage标志设置了PG_SLAB后,struct page中的部分成员可以用来描述slab对象.如下代码所示(由于struct page成员很多,下面只将描述slab对象有关的成员列出):

//为了节省内存,struct page中许多结构体会通过union联合体进行封装,此处做了省略
struct page {
	/* First double word block */
    //当页描述符成员flage标志设置了PG_SLAB后,struct page中对应的slab成员才有效
	unsigned long flags;		/* Atomic flags, some possibly updated asynchronously */
	void *s_mem;			/* slab first object */
    //freelist实际上是一个数组,数组中存放slab中未使用的obj的index值
	void *freelist;		/* sl[aou]b first free object */
		/* page_deferred_list().prev	-- second tail page */
	//当前slab已经使用的obj数量
	unsigned int active;		/* SLAB */
    
    /* 通过该成员将链到slab cache对应节点kmem_cache_node所管理的3个链表上*/
	struct list_head lru;	/* Pageout list, eg. active_list
					 * protected by zone_lru_lock !
					 * Can be used as a generic list
					 * by the page owner.
					 */
    
    //指向slab的slab cache描述符kmem_cache
	struct kmem_cache *slab_cache;	/* SL[AU]B: Pointer to slab */
    
    //slab首地址,待验证
    void *virtual;
	
}

由上面代码可以看出在slab描述符中最重要两个数据结构是s_mem和freelist这两个成员。

  1. s_mem用于指向指定slab区域中第一个obj(slab由一个或多个连续的页构成,由伙伴系统分配的内存块,固一个slab包含页的个数为2^gfp_order)
  2. freelist指向的是slab空闲obj的索引数组,该数组要和slab描述符中的active成员搭配使用。freelist指向的区域是一个连续地址的数组,它保存的地方有两种情况:一种情况是放在slab自身所在的内存区域,另外一种情况是保存在slab所在内存区域的外部(若保存在slab外部,则保存在slab对应slab cache的kmem_cache结构体中freelist_cache成员指针指向的链表).

下面介绍slab的空闲索引数组保存在slab自身内部的情况slab描述符是如何管理slab和其内部obj,如下图所示:

在这里插入图片描述

通过示意图来描述slab如何根据freelist数组和active成员来分配和释放其内部的空闲obj的(假设该slab中有6个obj)。

在这里插入图片描述

在slab机制中slab管理的内存区域的连续页块数,和slab cache结构描述符struct kmem_cache中的gfporder有关。该gfp是在slab cache初始化时通过每个slab中obj的数量和大小,着色区大小,freelist大小,slab对象描述符大小等一系列数据计算而来。需要注意的是这些对象的大小并不是创建的时候对象本身的大小,系统为了优化内存访问还会做一些字节对齐的填充,或者是在对象交界处填充一些magicnum进行防越界处理(如red_zone).

3.slab分配器中各个重要结构体间的关系总结

在这里插入图片描述

通过上图我们对slab分配器中各个重要结构体间的关系做一个总结:

  1. slab机制中每个slab cache对应一个struct kmem_cache结构体,linux内核中会分配一个静态全局的struct kmem_cache变量slab_caches,该指向一个双向链表,内核中所有的slab cache的结构描述符都会挂到该链表中(通过list成员变量接入slab_caches链表)。我们可以在shell中断通过/proc/slabinfo查看内核中所有slab cache的相关数据信息。

    / # cat /proc/slabinfo
    slabinfo - version: 2.1
    # name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> >
    zswap_entry            0      0    360   22    2 : tunables    0    0    0 : slabdata      0      0      0
    sw_flow_stats          0      0    448   18    2 : tunables    0    0    0 : slabdata      0      0      0
    		......
    		......
    		......
    
    dma-kmalloc-64         0      0    368   22    2 : tunables    0    0    0 : slabdata      0      0      0
    dma-kmalloc-32         0      0    336   24    2 : tunables    0    0    0 : slabdata      0      0      0
    dma-kmalloc-16         0      0    320   25    2 : tunables    0    0    0 : slabdata      0      0      0
    dma-kmalloc-8          0      0    312   26    2 : tunables    0    0    0 : slabdata      0      0      0
    dma-kmalloc-192        0      0    496   16    2 : tunables    0    0    0 : slabdata      0      0      0
    dma-kmalloc-96         0      0    400   20    2 : tunables    0    0    0 : slabdata      0      0      0
    kmem_cache_node      213    216    448   18    2 : tunables    0    0    0 : slabdata     12     12      0
    kmem_cache           216    224    576   28    4 : tunables    0    0    0 : slabdata      8      8      0
    
    
  2. 每个slab cache的描述符(struct kmem_cache)中会包含一个Per-CPU结构struct array_cache,该结构体用来作为对应slab cache对象的本地CPU高速缓存,缓存的对象是slab obj.

  3. 每个slab cache的描述符中还包含了一个struct kmem_cache_node数组成员node:

    1. node数组长度为系统内存节点个数,也就是每个slab cache会给os的每个内存节点分配一个kmem_cache_node结构体(node[nodeid]),kmem_cache_node结构体用来缓存和管理对应内存节点中的所有slab。
    2. 每个kmem_cache_node结构中包含3个链表slabs_partial、slabs_full和slabs_free,每个链表存储的都是对应内存节点中的slab描述符。其中slabs_partial链表中存储的slab既包含空闲的 slab obj,也包含已经被使用的slab obj。slabs_full链表中的slab只包含处于使用状态的slab obj。而slab_free链表中的slab则只包含处于空闲状态的slab
    3. 每个kmem_cache_node结构中还存在一个其他node共享的stuct array_cache成员shared,shared成员中的entry数组存储的是本内存节点中部分的slab obj,这些slab obj能被系统中的其他内存节点共享(本质是其他内存节点对应的cpu也能访问这些slab obj)
  4. slab的描述符共用了页的结构描述符struct page,此时struct page中的flage标志成员置位了PG_SLAB位。

    1. 每个slab cache包含了一个或多个slab,同一个slab cache中的slab指向的内存区域大小一样(2^gfporder),且slab内部包含的slab obj数量也一样。

    2. slab描述符(struct page)中的s_mem成员指向了slab中第一个obj(存储obj的首地址),而freelist成员指向了slab的空闲obj索引数组,它结合描述符中的active成员就能获取第一个空闲obj在s_mem指向内存区域的索引。

    3. slab着色区的作用是为了错开不同的slab,让CPU更有效的缓存slab。

      (1).通过slab着色(slab coloring), slab分配器能够均匀地在缓存中分布对象, 以实现均匀的缓存利用
      (2).经常使用的内核对象保存在CPU高速缓存中,这是我们想要的效果。从`slab`分配器的角度进行衡量, 伙伴系统的高速缓存和TLB占用较大,
            这是一个负面效应,因为这会导致不重要的数据驻留在`CPU`高速缓存中, 而重要的数据则被置换到内存, 显然应该防止这种情况出现.
      (3).着色这个术语是隐喻性的. 它与颜色无关, 只是表示slab中的对象需要移动的特定偏移量, 以便使对象放置到不同的缓存行.
      
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[内核内存] slab分配器1---slab机制详解 的相关文章

随机推荐

  • 关于encodeURI两次转码和非两次转码,以及后台中文,前台不显示问题总结

    一 js 如果中文乱码 就转码两次 function details cellValue row return a href font color 6495ED 详情 font a 二 后台中文前台不显示 就用这个方法 response a
  • SpringCloud 微服务架构

    目前微服务架构还是比较火的 但是 为什么会选择springcloud 作为 微服务架构呢 列如 dubbo Motan 等等技术都是比较多的 但是依然springcloud 占据了很大一部分 值得深思 目录 一 选型依据 二 目前微服务架构
  • powershell怎么运行_PowerShell 美化及自定义

    内容并不是借助第三方脚本实现 是讲的如何DIY PowerShell 首先 更加美观的Windows Terminal 唐铭 Windows Terminal 终端入门 zhuanlan zhihu com 修改PowerShell的显示效
  • 苹果手机无线网显示无网络连接到服务器,iPhone提示:“无线局域网似乎未接入互联网”,咋回事?...

    我的iPhone怎么用着用着偶尔就会出现弹窗提示 无线局域网似乎未接入互联网 这个是怎么回事呀 是不是无线网络出问题了啊 咦 点击弹窗底部的 继续尝试使用无线局域网 后 Wi Fi又可继续正常使用 咋回事呀这个 针对这个问题小锐在与多个客户
  • ns修改服务器,修改你的域名ns服务器地址

    修改你的域名ns服务器地址 内容精选 换一换 域名的DNS服务器定义了域名用于解析的权威DNS服务器 通过华为云注册成功的域名默认使用华为云DNS进行解析 详细内容 请参见华为云DNS对用户提供域名服务的DNS是什么 若您选择非华为云DNS
  • Jupyter设置指定的python环境

    Jupyter设置指定的python环境 Jupyter在虚拟环境中启动 按理说在命令行执行如下命令 conda activate 环境名称 激活一个conda环境 再打开jupyter 输入如下命令 jupyter notebook 默认
  • mycat 分片规则-枚举分片-hash-int

    为方便测试 本实例在以下案例中测试https blog csdn net qq 41712271 article details 114984855 spm 1001 2014 3001 5501 通过在配置文件中配置可能的枚举值 指定数据
  • 5G MEC如何产生:从标准演进看云网融合

    01 概 述 5G MEC这个表述并不精确 两者相互成就 而非相互从属 说5G MEC 是因为随着5G的演进 MEC也在焕发新生 寻根溯源 与5G MEC相关的最重要的标准组织有三个 ITU International Telecommun
  • git 放弃本地修改,强制拉取更新

    原文链接 https blog csdn net haoaiqian article details 78284337 开发时 对于本地的项目中修改不做保存操作 或代码改崩 可以用到Git pull的强制覆盖 具体代码如下 git fetc
  • 转-各种排序动图

    1 快速排序 介绍 快速排序是由东尼 霍尔所发展的一种排序算法 在平均状况下 排序 n 个项目要 n log n 次比较 在最坏状况下则需要 n2 次比较 但这种状况并不常见 事实上 快速排序通常明显比其他 n log n 算法更快 因为它
  • 数据库设计与优化 - MySQL优化策略

    MySQL服务器操作层架构 MySQL语句的优化就发生MySQL Server服务器架构的操作层 这层具体的执行流程是 这层主要的功能是 SQL 语句的解析 优化 缓存的查询 MySQL 内置函数的实现 跨存储引擎功能 所谓跨存储引擎就是说
  • 如何防止uniswap/pancakeswap被机器人夹

    被机器人夹是通俗说法 实际就是 front running 抢先提前交易 具体就是机器人在链上侦测到你有买入行为的时候 他立刻买 gas给的比你高 快你一步确认 这样你成交价就高了 因为dex有滑点 所以你依旧会以高一点的价格成交并且再将价
  • 「PAT乙级真题解析」Basic Level 1002 (问题分析+完整步骤+伪代码描述+提交通过代码)

    乙级的题目训练主要用来熟悉编程语言的语法和形成良好的编码习惯和编码规范 从小白开始逐步掌握用编程解决问题 PAT乙级BasicLevelPractice 1002 问题分析 方案一 模拟 题目直接给定了步骤 用模拟法将给定步骤写成代码逻辑是
  • C++primer十五章笔记15.7构造函数与拷贝控制

    15 7构造函数与拷贝控制 位于继承体系中的类也需要控制当其对象执行一系列操作时发生什么样的行为 创建 拷贝 移动 赋值和销毁 如果一个类没有定义拷贝控制操作 则编译器会给出一个合成的版本 可以被定义为被删除的函数 15 7 1虚析构函数
  • webrtc scoped_refptr、C++智能指针(防忘记录)

    C 智能指针有三种 shared ptr unique ptr weak ptr 具体说明参见 防忘链接 https www cnblogs com wxquare p 4759020 html webrtc的scoped refptr类似
  • maven下载不到源码:Cannot download sources Sources not found for:

    记录下记录下 很神奇的问题 也不去深究了 解决就行 侧重点不在这 就把方法记录下了 文章目录 问题 问题排查 方案一 Maven的镜像换一换试一试 方案二 删掉工程下的缓存和IDE配置文件 方案三 找个能下载源码的同事或环境换上它的mave
  • 图神经网络入门推荐好文(附GNN大佬资料包下载福利)

    今天想和大家分享的是图卷积神经网络 随着人工智能发展 很多人都听说过机器学习 深度学习 卷积神经网络这些概念 但图卷积神经网络 却不多人提起 那什么是图卷积神经网络呢 简单的来说就是其研究的对象是图数据 Graph 研究的模型是卷积神经网络
  • 信息收集-服务器信息

    服务器上面可以运行大量的系统服务和第三方应用服务 如果操作系统或者第三方软件没有及时升级打补丁 攻击者就有可能直接通过服务器上运行的服务进行攻击 服务器需要收集的信息包含三个方面 操作系统信息等识别 waf Web应用程序防火墙 CMS 内
  • 有没有哪个瞬间,让你突然对ChatGPT感到失望?

    不知道你是否和我一样 在第一次使用ChatGPT输入Prompt 并得到答复的那一刻 都会忍不住地赞叹一句 握草 但随着时间慢慢拉长 体验不断深入 想法也会慢慢改变 主题图 by Midjourney Prompt The moment o
  • [内核内存] slab分配器1---slab机制详解

    文章目录 1 slab分配器原理 2 slab分配器重要数据结构以及组织关系 2 1 slab cache描述符struct kmem cache 2 2 slab描述符struct page 3 slab分配器中各个重要结构体间的关系总结