内存管理机制SLAB

1. 为什么需要内存分配管理?为什么需要SLAB?

  • 在学习c语言时,我们常常会使用到malloc()去申请一块内存空间,用于存放我们的数据,这是代码层面的语言

  • 如果我们想要关心malloc这个命令向系统发出后,系统会做什么呢?系统会给这个变量分配一个内存空间。那么系统是如何分配的呢,这就需要了解系统的内存分配管理方法了。

  • 在linux中,最先推出用于分配内存的管理单元和算法是伙伴分配器(buddy allocator),它是以页为单位管理和分配内存,最小分配一页,也就是4KB 大小。而可能内核的需求只是以字节为单位。

    • 假如我们需要动态申请一个内核结构体(占 20 字节),若仍然分配一页内存,这将严重浪费内存。这也将会导致内部碎片问题
  • 这时候就出现了slab分配器,它专门用于分配小内存,分配内存以字节为单位,基于伙伴分配器的大内存进一步细分成小内存分配。

    • 概括来讲:slab 分配器仍然从buddy分配器中申请内存,之后自己对申请来的内存细分管理。从而达到减少内存碎片化的目的。
    • 形象概括:buddy分配器理解成一个仓库,slab分配器理解为一个商店,仓库给商店进行批发的货物,商店从仓库进货以后,再零售给消费者(使用kmalloc的用户)
      在这里插入图片描述
  • SLAB分配器内存管理机制的核心思想:

    • 提供小内存,减少内存碎片
    • 维护常用对象的缓存
    • 提高CPU硬件缓存的利用率
  • 随着时间的推移,SLAB分配器演变成SLUB和SLOB分配器

2. SLAB底层机制

2.1 基本概念

2.1.1 Slab

  • 是SLAB机制中的基本组成单元,它是预先分配的一块连续的内存区域
  • 每个Slab由一个或多个大小相同的对象组成,这些对象属于同一个Cache。
  • Slab可以处于三种状态之一:满(full),部分满(partial)和空(empty)。
  • 系统优先从部分满的Slab中分配对象,以提高内存利用率。

2.1.2 Slab Cache

  • Slab Cache专门用于管理一种特定大小和类型的对象。
  • 每个Slab Cache都由多个Slab组成,它们共同组成了该类型对象的存储池。
  • 通过Slab Cache,系统可以快速地分配和释放对象,避免了每次分配时都进行昂贵的内存搜索和设置操作。
  • 主要负责三个事情:
    • 对象缓存:缓存常用对象,加快分配速度。
    • 内存管理:根据需要增加或释放Slab,优化内存使用。
    • 碎片最小化:通过维护大小相同的对象集合,减少内存碎片。

2.1.3 缓冲色彩(Cache Coloring)

  • 缓存色彩是一种用于优化CPU缓存利用率的技术。通过对内存分配的微小调整,它能减少不同Slab中对象的缓存行冲突。

2.1.4 构造器和析构器

  • 为了进一步提高效率,SLAB机制允许为每种类型的对象定义构造器(Constructor)和析构器(Destructor)。构造器在对象第一次被创建时被调用,用于初始化对象。析构器在对象最终被释放回系统前被调用,用于执行必要的清理工作。通过这种方式,SLAB机制确保了资源的有效利用和稳定的性能表现。

2.2 结构定义

2.2.1 slab分配的内存大小

  • 问题:Linux中采用4KB大小的页框作为标准的内存分配单元,在实际应用中,经常需要分配一组连续的页框,而频繁的申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的空闲页框,这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。
  • Linux内核引入了伙伴系统算法来避免这种情况。其把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1、2、4、8、16、32、64、128、256、512和1024个连续页框的页框块。最大可以申请1024个连续页框,也即4MB大小的连续空间。
  • 而slab则基于伙伴系统,进一步将页框划分成各个小的内存块,而他的实现则是通过在kmem_cache_init过程中,通过kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE]来建立caches数组
void __init kmem_cache_init(void){kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE] = create_kmalloc_cache(kmalloc_info[INDEX_NODE].name[KMALLOC_NORMAL],kmalloc_info[INDEX_NODE].size,ARCH_KMALLOC_FLAGS, 0,kmalloc_info[INDEX_NODE].size);...create_kmalloc_caches(ARCH_KMALLOC_FLAGS);
}
  • kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE]中的INDEX_NODE即为kmalloc_index,INDEX_NODE取值范围为0-21,分别存放着不同大小的内存caches
static __always_inline unsigned int __kmalloc_index(size_t size, bool size_is_constant){/* 0 = zero alloc */if (!size)return 0;if (size <= KMALLOC_MIN_SIZE)return KMALLOC_SHIFT_LOW;/* 1 =  65 .. 96 bytes分配65-96bytes的内存大小的块*/if (KMALLOC_MIN_SIZE <= 32 && size > 64 && size <= 96)return 1;/* 2 = 129 .. 192 bytes分配65-96bytes的内存大小的块*/if (KMALLOC_MIN_SIZE <= 64 && size > 128 && size <= 192)return 2;/* n = 2^(n-1)+1 .. 2^n 分配2^(n-1)+1 .. 2^n大小内存的块内存*/if (size <= 8) return 3;if (size <= 16) return 4;if (size <= 32) return 5;if (size <= 64) return 6;if (size <= 128) return 7;if (size <= 256) return 8;if (size <= 512) return 9;if (size <= 1024) return 10;if (size <= 2 * 1024) return 11;if (size <= 4 * 1024) return 12;if (size <= 8 * 1024) return 13;if (size <= 16 * 1024) return 14;if (size <= 32 * 1024) return 15;if (size <= 64 * 1024) return 16;if (size <= 128 * 1024) return 17;if (size <= 256 * 1024) return 18;if (size <= 512 * 1024) return 19;if (size <= 1024 * 1024) return 20;if (size <= 2 * 1024 * 1024) return 21;if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES) && size_is_constant)BUILD_BUG_ON_MSG(1, "unexpected size in kmalloc_index()");elseBUG();return -1;
}
  • 通过create_kmalloc_cache创建出对应的内存区域,且它们对应着0,96byte,192byte,8byte,16byte,32byte,64byte . . . 2M的连续内存空间。

2.2.2 slab分配的内存类型

  • 内存类型则由kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE]中的KMALLOC_NORMAL决定,可选诸如KMALLOC_NORMAL、KMALLOC_DMA、KMALLOC_CGROUP、NR_KMALLOC_TYPES、KMALLOC_RECLAIM等,也可以由用户自己定义自己的专用内存类型,诸如kvm_vcpu、dquot、signal_cache等等都是其他模块自行定义的内存类型。
enum kmalloc_cache_type {/* 对应着kmalloc的内存 */KMALLOC_NORMAL = 0,
#ifndef CONFIG_ZONE_DMAKMALLOC_DMA = KMALLOC_NORMAL,
#endif#ifndef CONFIG_MEMCG_KMEMKMALLOC_CGROUP = KMALLOC_NORMAL,
#endif#ifdef CONFIG_SLUB_TINYKMALLOC_RECLAIM = KMALLOC_NORMAL,
#elseKMALLOC_RECLAIM,
#endif#ifdef CONFIG_ZONE_DMA/* 对应着dma-kmalloc的内存 */KMALLOC_DMA,
#endif#ifdef CONFIG_MEMCG_KMEMKMALLOC_CGROUP,
#endifNR_KMALLOC_TYPES
};

2.2.3 基本结构

在这里插入图片描述

  • kmem_cache数据结构代表一个slab 缓存
  • kmem_cache_cpu表示了每个 CPU 对象的缓存信息。它用于存储每个 CPU 上的缓存数组(array_cache)以及一些与 CPU 相关的缓存统计信息
  • array_cache用于表示该缓存在各个CPU中的slab对象
  • kmem_cache_node用于管理各个内存节点上slab对象的分配
    在这里插入图片描述
kmem_cache
struct kmem_cache {struct array_cache __percpu *cpu_cache;  //表示每个cpu中的slab对象unsigned int batchcount; //当cpu_cache为空时,从缓存slab中获取的对象数目,它还表示缓存增长时分配的对象数目。//初始时为1,后续会调整unsigned int limit; //cpu_cache中的对象数目上限//当slab free达到limit时,需要将array_caches中的部分obj返回到kmem_cache_node的页帧中unsigned int shared; //表示该缓存是否是共享的unsigned int size; //表示slab中的每个对象大小struct reciprocal_value reciprocal_buffer_size; //用于存储一个缓存的倒数大小的数据结构slab_flags_t flags; //用于存储常量标志的位掩码unsigned int num;   //每个slab中的对象数目unsigned int gfporder; //slab关联页数gfp_t allocflags;  //强制使用的 GFP 标志,例如 GFP_DMAsize_t colour;   //缓存颜色范围unsigned int colour_off;  //颜色偏移量struct kmem_cache *freelist_cache; // 空闲对象管理unsigned int freelist_size; // 空闲对象数量//构造函数指针void (*ctor)(void *obj); //这个在2.6之后已经废弃了const char *name;      //缓存名称struct list_head list; //用于将缓存连接到全局缓存列表的链表节点int refcount;          //引用计数int object_size;       //对象的大小int align;             //对齐方式#ifdef CONFIG_DEBUG_SLABunsigned long num_active;       //活动对象的数量unsigned long num_allocations;  //分配的对象数量unsigned long high_mark;        //高水位标记unsigned long grown;            //已增长的对象数量unsigned long reaped;           //已收割的对象数量unsigned long errors;           //错误数量unsigned long max_freeable;     //最大可释放的空闲数量unsigned long node_allocs;      //节点分配数量unsigned long node_frees;       //节点释放数量unsigned long node_overflow;    //节点溢出数量atomic_t allochit;              //分配命中计数 atomic_t allocmiss;             //分配未命中计数atomic_t freehit;               //释放命中计数atomic_t freemiss;              //释放未命中计数#ifdef CONFIG_DEBUG_SLAB_LEAKatomic_t store_user_clean;
#endifint obj_offset; //对象偏移量
#endif #ifdef CONFIG_MEMCGstruct memcg_cache_params memcg_params; //用于内存控制组的参数
#endif#ifdef CONFIG_KASANstruct kasan_cache kasan_info; //KASan 相关信息
#endif#ifdef CONFIG_SLAB_FREELIST_RANDOMunsigned int *random_seq;  //用于slab freelist随机化的随机序列
#endifunsigned int useroffset;   //用户复制区域的偏移量unsigned int usersize;     //用户复制区域的大小struct kmem_cache_node *node[MAX_NUMNODES];  //每个内存节点上的slab对象信息,每个node上包括部分空闲,全满以及全部空闲三个队列
};
keme_cache_cpu
struct kmem_cache_cpu{void **freelist;        //指向下一个可用的objectunsigned long tid;      //全局独一无二的事物IDstruct page *page;      //slab内存的page指针#ifdef CONFIG_SLUB_CPU_PARTIALstruct page *partial;   //本地slab partial链表,主要是一些部分使用object的slab
#endif
};
array_cache
  • array_cache是一个per_cpu数组,访问不需要加锁,是与cpu cache打交道的直接数据结构,每次获取空闲slab对象时都是通过entry[avail--]去获取,当avail==0时,又从kmem_cache_node中获取batchcount个空闲对象到array_cache中。
struct array_cache {unsigned int avail; //保存了当前array中的可用数目unsigned int limit; //同上unsigned int batchcount; //同上unsigned int touched; //缓存收缩时置0,缓存移除对象时置1,使得内核能确认在上一次收缩之后是否被访问过void *entry[]; //用于存储缓存的条目的数组,大小在运行时动态确定
};     
kmem_cache_node
  • kmem_cache_node用于管理slab(实际对象存储伙伴页帧),其会管理三个slab列表:
    • 部分空闲partial
    • 全部空闲empty
    • 全部占用full
  • array_cache获取batchcount空闲对象时,先尝试从partial分配,如果不够则再从empty分配剩余对象,如果都不够,则需要grow分配新的slab页帧。
struct kmem_cache_node {spinlock_t list_lock;       //自旋锁,用于保护缓存节点的链表操作unsigned long nr_partial;   //slab节点中slab的数量struct list_head partial;   //slab节点的slab partial链表
};
struct page
  • 用于描述slab页面,一个slab页面由一个或多个page组成,page页帧是物理存储地址

2.3 工作原理

2.3.1 对象分配和释放过程

  • 三个指针:

    • current指针,仅指向一个slab
    • partial指针,指向未满slab链表
    • full指针,指向全满slab链表
      在这里插入图片描述
  • 对象分配:使用current slab,若满,从partial指向的slab中取空闲区域,把current指向的slab移到full

      1. 查找合适的Slab Cache:当系统需要一个特定类型的对象时,首先在对应的Slab Cache中查找。
      1. 选择Slab:在找到的Slab Cache中,系统会寻找状态为部分满(Partial)或空(Empty)的Slab。优先选择部分满的Slab,以提高内存利用率。
      1. 分配对象:从选定的Slab中分配一个空闲对象。如果选择的是空Slab,系统会先初始化该Slab,然后分配对象。
      1. 更新Slab状态:分配对象后,更新Slab的状态。如果所有对象都被分配,Slab状态变为满(Full)。
  • 对象释放:若是full则移动到partial,若partial全空则还给buddy分配器

      1. 确定对象所属的Slab:释放对象时,系统首先确定该对象属于哪个Slab。
      1. 释放对象:将对象标记为未使用,返回到Slab的空闲对象池中。
      1. 更新Slab状态:如果释放对象前Slab是满的,则释放后状态变为部分满(Partial)。如果释放后Slab中所有对象都是空闲的,则状态变为空(Empty)。
      1. Slab的回收:如果一个Slab长时间处于空状态,系统可能会决定回收该Slab,释放内存给操作系统。

2.3.2 缓存色彩和内存对齐

  • 缓存色彩:
    • 缓存色彩是一种用于优化CPU缓存利用率的技术。由于CPU缓存行的存在,不同的内存地址可能会映射到同一个缓存行,这种现象称为缓存行冲突。缓存色彩通过在对象的内存地址上加上小的偏移量,使得连续分配的对象不会映射到相同的缓存行上,从而减少缓存行冲突,提高缓存的使用效率。
  • 内存对齐:
    • 内存对齐是指按照一定的边界来分配内存地址,使得数据的存取更加高效。在处理器架构中,对齐的内存访问通常比非对齐的内存访问速度要快。SLAB内存管理机制通过确保对象在内存中正确对齐,提高了数据访问的速度,减少了内存访问时间。
    • 内存对齐的另一个好处是减少了系统的内存碎片。

3. SLAB、SLUB和SLOB

  • SLAB分配器:适用于内存分配和释放频繁,且需要稳定内存使用的环境。它的设计注重减少内存碎片和提高内存利用率,非常适合长时间运行的服务或系统。
  • SLUB分配器:适用于对性能要求高的场景,特别是在多核处理器上。它的设计简化了内存管理的数据结构,减少了锁的竞争,优化了CPU缓存的使用,提供了高效的内存分配。
  • SLOB分配器:适用于内存资源非常有限的环境,如嵌入式系统或老旧的硬件。它的设计优先考虑内存的紧凑使用,尽可能减少内存的浪费。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/799394.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决 VSCode 编辑器点击【在集成终端中打开】出现新的弹框

1、问题描述 在 VSCode 的项目下&#xff0c;鼠标右键&#xff0c;点击【在集成终端中打开】&#xff0c;出现新的一个弹框。新版的 VSCode 会有这个问题&#xff0c;一般来说我们都希望终端是在 VSCode 的控制台中打开的&#xff0c;那么如何关闭这个弹框呢&#xff1f; 2、解…

室友打团太吵?一条命令让它卡死

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;更多干货&#xff0c;请关注专栏《网络安全自学教程》 SYN Flood 1、hping3实现SYN Flood1.1、主机探测1.2、扫描端…

文本识别 OCR 解决方案

Capture2Text 便携式 OCR 工具 Capture2Text 能够使用键盘快捷键快速对屏幕的一部分进行 OCR。 默认情况下&#xff0c;生成的文本将保存到剪贴板。支持中文、英文、法文、德文、日文、韩文、俄文、西班牙文等 90 多种语言。 Capture2Text 是便携式工具&#xff0c;不需要安装…

数据库引论:4、使用E-R模型的数据库设计

4.1 设计过程概览 图1 开发数据库应用包含的任务 真实世界 ⇒ \Rightarrow ⇒概念模型 ⇒ \Rightarrow ⇒逻辑模型 ⇒ \Rightarrow ⇒物理模型 数据库设计&#xff1a; 概念设计(Conceptual design)&#xff1a; 用一个概念模型描述物理世界的一个主体 逻辑设计(Logical desi…

42.基于SpringBoot + Vue实现的前后端分离-服装销售平台管理系统(项目 + 论文)

项目介绍 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的交换和信息流通显得特别重要。因此&#xff0c;开发合适的服装销售平台成为企业必然要走的一步棋。开发合适的服…

场景文本检测识别学习 day01(传统OCR的流程、常见的损失函数)

传统OCR的流程 传统OCR&#xff1a;传统光学字符识别常见的的模型主要包括以下几个步骤来识别文本 预处理&#xff1a;预处理是指对输入的图像进行处理&#xff0c;以提高文字识别的准确率。这可能包括调整图像大小、转换为灰度图像、二值化&#xff08;将图像转换为黑白两色&…

学习人工智能:为何PyTorch深度学习框架不可或缺

在人工智能&#xff08;AI&#xff09;的浩瀚领域中&#xff0c;深度学习作为其核心分支&#xff0c;正以其强大的数据处理能力、模式识别能力和预测能力引领着科技的飞速发展。而在深度学习的众多工具与框架中&#xff0c;PyTorch无疑是一颗璀璨的明星。本文将从PyTorch的特点…

【WSN覆盖优化】基于灰狼优化算法的无线传感器网络覆盖 GWO-WSN覆盖优化【Matlab代码#74】

文章目录 【可更换其他算法&#xff0c;获取资源请见文章第5节&#xff1a;资源获取】1. 灰狼优化算法2. WSN节点感知模型3. 部分代码展示4. 仿真结果展示5. 资源获取 【可更换其他算法&#xff0c;获取资源请见文章第5节&#xff1a;资源获取】 1. 灰狼优化算法 此处略。 2.…

推动科技创新润德生物邀您到场参观2024第13届生物发酵展

参展企业介绍 山东润德生物科技有限公司成立于2014年10月17日&#xff0c;是一家围绕生物制品的研发、生产、营销、国际贸易、技术服务为核心业务的国家高新技术企业&#xff0c;近年来荣获国家制造业单项冠军示范企业、国家级绿色工厂、国家知识产权优势企业、国家工业产品绿…

目标跟踪——行人检测数据集

一、重要性及意义 目标跟踪和行人检测是计算机视觉领域的两个重要任务&#xff0c;它们在许多实际应用中发挥着关键作用。为了推动这两个领域的进步&#xff0c;行人检测数据集扮演着至关重要的角色。以下是行人检测数据集的重要性及意义的详细分析&#xff1a; 行人检测数据…

4核8G服务器性能怎么样?4核8G12M配置可应对哪些场景?

腾讯云4核8G服务器多少钱&#xff1f;腾讯云4核8G轻量应用服务器12M带宽租用价格646元15个月&#xff0c;活动页面 txybk.com/go/txy 活动链接打开如下图所示&#xff1a; 腾讯云4核8G服务器优惠价格 这台4核8G服务器是轻量应用服务器&#xff0c;详细配置为&#xff1a;轻量4核…

基于Spring Boot+Vue的汽车销售系统

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统汽车销售信息管理难度大&#xff0c;容错率低&#xff0…

【Linux】达梦数据库安装部署(附详细图文)

目录 一、安装前的准备工作 1.检查操作系统配置 &#xff08;1&#xff09;获取系统位数 getconf LONG_BIT &#xff08;2&#xff09;查看操作系统release信息 cat /etc/system-release &#xff08;3&#xff09;查询系统名称 uname -a &#xff08;4&#xff09;查看操…

VS Code远程连接服务器运行python程序

之前一直用pycharm连接服务器跑程序&#xff0c;pycharm需要本地和远程都存一份代码&#xff0c;然后把本地的更新同步到服务器上来实现代码修改&#xff0c;后来实习的时候发现企业里面都用VS Code&#xff0c;不得不说&#xff0c;VS Code真的很方便&#xff0c;直接连服务器…

「媒体宣传」科技IT行业有哪些媒体邀约资源-51媒体网

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 科技IT行业的媒体邀约资源非常丰富&#xff0c;包括了各种类型的传统媒体和新兴的网络媒体平台。以下是一些主要的媒体邀约资源&#xff1a; 除此之外&#xff0c;还有一些其他科技类网络…

算法 第34天 贪心3

1005 K 次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以这种方式修改数组后&#xff0c;返回数组 可能…

Failed to start docker.service: Unit is not loaded properly: Invalid argument.

Failed to start docker.service: Unit is not loaded properly: Invalid argument. 未知原因&#xff1a;docker服务无法正常load 解决方式&#xff1a; 卸载docker&#xff0c; 删除docker.service 重新安装docker Docker是一种相对使用较简单的容器&#xff0c;我们可以通过…

【QT+QGIS跨平台编译】063:【qca-softstore+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、qca-softstore介绍二、QCA下载三、文件分析四、pro文件五、编译实践5.1 windows下编译5.2 linux下编译5.3 macos下编译一、qca-softstore介绍 QCA-Softstore 是一个软件证书存储插件,它是为 QCA 框架设计的。这个插件提供了一个简单的持久化证书…

SpringCloud Alibaba Sentinel 规则持久化

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十七篇&#xff0c;即使用 Sentinel 实现规则持久化。 二、概述 从前面我们做的实验可知&#xff0c;…

循环双链表算法库构建

学习贺老师数据结构数据结构之自建算法库——循环双链表_数据结构编写一个程序linklist.cpp-CSDN博客 模仿单链表逻辑,实现双链表, 大差不差 v1.0: 实现基本功能 V1.0 1.主要功能: //(1)头插法建立循环双链表 void Create_Double_CyclicList_Head(DoubleLinkList_Cyclic *&am…