Linux内存管理

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. 合并的要求太过严格,只能是满足伙伴关系的块才能合并,比如第1块和第2块就不能合并。

  2. 碎片问题:一个连续的内存中仅仅一个页面被占用,导致整块内存区都不具备合并的条件

  3. 浪费问题:伙伴算法只能分配2的幂次方内存区,当需要8K(2页)时,好说,当需要9K时,那就需要分配16K(4页)的内存空间,但是实际只用到9K空间,多余的7K空间就被浪费掉。

  4. 算法的效率问题: 伙伴算法涉及了比较多的计算还有链表和位图的操作,开销还是比较大的,如果每次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区域。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# sudo cat /proc/buddyinfo
Node 0, zone      DMA      1      0      1      0      0      0      1      0      0      1      3
Node 0, zone    DMA32   1380   1417   2611   6972   3703   1978    585      7      0      0      0
Node 0, zone   Normal  90233 1147352 1517090 1219299 740669 285583  49056   2098     13      0      0
Node 1, zone   Normal 159797 625159 907571 870913 650684 360921 124162  20515    867      4      0


# extfrag_index文件中显示的数值是除以1000后的结果,当数值越接近1则表示碎片越多,数值越接近-1则表示碎片越少
$ sudo cat /sys/kernel/debug/extfrag/extfrag_index
Node 0, zone      DMA -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000
Node 0, zone    DMA32 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.979 0.990
Node 0, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.989 0.995
Node 1, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.993

# 
$ sudo cat /sys/kernel/debug/extfrag/unusable_index
Node 0, zone      DMA 0.000 0.000 0.000 0.001 0.001 0.001 0.001 0.018 0.018 0.018 0.159
Node 0, zone    DMA32 0.000 0.005 0.013 0.042 0.276 0.527 0.797 0.960 1.000 1.000 1.000
Node 0, zone   Normal 0.000 0.000 0.068 0.211 0.439 0.714 0.923 0.994 0.999 1.000 1.000
Node 1, zone   Normal 0.000 0.004 0.041 0.126 0.286 0.521 0.777 0.945 0.996 0.999 1.000

# 被动清理内存碎片, 内核配置需配置:CONFIG_COMPACTION=y
$ sudo echo 1 > /proc/sys/vm/compact_memory

# 主动清理, 清空cache/buffer/memory
$ sudo sync
$ sudo echo 3 > /proc/sys/vm/drop_caches

参考

  1. 【小工具】 - linux内存碎片检查和清理_巨魔战将-CSDN博客

  2. Linux是如何避免内存碎片的_aurorayqz的博客-CSDN博客_内存碎片

updatedupdated2024-05-152024-05-15