Linux内存管理
简介
kernel的内存管理是个2层分层系统,从下往上依次为:
- 第一层为全部物理内存:其管理器为伙伴系统,最小管理单位为page;
- 第二层为slab page:其管理器为slab/slub,最小管理单位为2的m次幂的字节块;
Buddy算法基本原理
伙伴算法(Buddy system)把所有的空闲页框分为11个块链表,每块链表中分布包含特定的连续页框地址空间,第0个块链表包含大小为2 ^ 0个连续的页框,第1个块链表中,每个链表元素包含2 ^ 1个页框大小的连续地址空间,….,第10个块链表中,每个链表元素包含2 ^ 10个页框大小的连续地址空间。每个链表中元素的个数在系统初始化时决定,在执行过程中,动态变化。
伙伴算法每次只能分配2的幂次页的空间,比如一次分配1页,2页,4页,8页,…,1024页(2^10)等等,每页(pageSize)大小一般为4K,因此,伙伴算法最多一次能够分配4M的内存空间。
两个内存块,大小相同,地址连续,同属于一个大块区域。(第0块和第1块是伙伴,第2块和第3块是伙伴,但第1块和第2块不是伙伴)
内核空间分为三种区,DMA,NORMAL,HIGHMEM,对于每一种区,都有对应的伙伴算法。
特点
优点:
较好的解决外部碎片问题
当需要分配若干个内存页面时,用于DMA的内存页面必须连续,伙伴算法很好的满足了这个要求
只要请求的块不超过512个页面(2K),内核就尽量分配连续的页面。
缺点:
合并的要求太过严格,只能是满足伙伴关系的块才能合并,比如第1块和第2块就不能合并。
碎片问题:一个连续的内存中仅仅一个页面被占用,导致整块内存区都不具备合并的条件
浪费问题:伙伴算法只能分配2的幂次方内存区,当需要8K(2页)时,好说,当需要9K时,那就需要分配16K(4页)的内存空间,但是实际只用到9K空间,多余的7K空间就被浪费掉。
算法的效率问题: 伙伴算法涉及了比较多的计算还有链表和位图的操作,开销还是比较大的,如果每次2 ^ n大小的伙伴块就会合并到2 ^ (n+1)的链表队列中,那么2 ^ n大小链表中的块就会因为合并操作而减少,但系统随后立即有可能又有对该大小块的需求,为此必须再从2 ^ (n+1)大小的链表中拆分,这样的合并又立即拆分的过程是无效率的。
Slab算法
高速缓存Slab层 slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内存碎片,而且处理速度也太慢。 而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免这些内碎片。slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当以后又要请求新的对象时,就可以从内存直接获取而不用重复初始化。 对象高速缓存的组织如右下图所示,高速缓存的内存区被划分为多个slab,每个slab由一个或多个连续的页框组成,这些页框中既包含已分配的对象,也包含空闲的对象。 在cache和object中加入slab分配器,是在时间和空间上的折中方案。
slab分配算法
slab分配算法采用cache 存储内核对象。当创建cache 时,起初包括若干标记为空闲的对象。对象的数量与slab的大小有关。开始,所有对象都标记为空闲。当需要内核数据结构的对象时,可以直接从cache 上直接获取,并将对象初始化为使用。 下面考虑内核如何将slab分配给表示进程描述符的对象。在Linux系统中,进程描述符的类型是struct task_struct ,其大小约为1.7KB。当Linux 内核创建新任务时,它会从cache 中获得struct task_struct 对象所需要的内存。Cache 上会有已分配好的并标记为空闲的struct task_struct 对象来满足请求。 Linux 的slab 可有三种状态: 满的:slab 中的所有对象被标记为使用。 空的:slab 中的所有对象被标记为空闲。 部分:slab 中的对象有的被标记为使用,有的被标记为空闲。 slab 分配器首先从部分空闲的slab 进行分配。如没有,则从空的slab 进行分配。如没有,则从物理连续页上分配新的slab,并把它赋给一个cache ,然后再从新slab 分配空间。 ———————————————— 版权声明:本文为CSDN博主「aurorayqz」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/aurorayqz/article/details/79671785
内存碎片检查方法
buddyinfo是linuxbuddy系统管理物理内存的debug信息。在linux中使用buddy算法解决物理内存的外碎片问题,其把所有空闲的内存,以2的幂次方的形式,分成11个块链表,分别对应为1、2、4、8、16、32、64、128、256、512、1024个页块。而Linux支持NUMA技术,对于NUMA设备,NUMA系统的结点通常是由一组CPU和本地内存组成,每一个节点都有相应的本地内存,因此buddyinfo 中的Node0表示节点ID;而每一个节点下的内存设备,又可以划分为多个内存区域(zone),因此下面的显示中,对于Node0的内存,又划分类DMA、Normal区域。
|
|