linux kernel heap
Buddy System
伙伴系统
采用二分法分配内存
分配的内存大小必须是2的整数次幂,2的指数(幂)就称为一个块的order。
块的大小单位为一个页的大小,比如一个页为4k的系统,order为0的堆块的大小就是(2^0)*4K。
分配连续的物理空间
memory zone
DMA and DMA32 zones, highmem zone and a Normal zone and other zones
vmalloc 的分配的空间在虚拟内存下时连续的,但是不一定要在物理内存下时连续的。
通过/proc/buddyinfo和/proc/pagetypeinfo查看分配的情况
1 | / # cat /proc/buddyinfo |
分配
首先有个大堆块
当分配时首先确定需要的块大小(确定需要那个oder的块)
如果当前的order有剩余的块则分配值,否则将order更大的块进行切分
Linux中通过get_free_pages实现
释放
当有块释放时,检查相邻的块(从同一个块中切分出来的),就将其合并成更大的order的块。
Linux中通过alloc_pages实现
buddy allocator
分配页的函数在”linux/gfp.h”中(gfp是get free page的意思),其中 gfp_mask是alloc_pages用来表示谁来请求这次的内存分配。比如GFP_KERNEL用来表示这个页框是在内核中使用的,GFP_USER表示在用户空间使用。
1 |
|
释放页
1 | void free_pages(unsigned long addr, unsigned int order) |
slab
slabs_full 完全分配的slab
slabs_partital 部分分配的slab
slabs_empty 空空的slab
SLAB: 从伙伴系统分配的 2^order 个物理页就组成了一个 SLAB ,而后续的操作就是在这个 SLAB 上在进行细分的,具体的结构体是 struct slab 。
每个kmem_cache里面包含的很多slab结构,同一个kmem_cache中包含的obj的大小都是相同的,每个slab只针对一种数据类型
每个slab结构中可以包含很多的obj
每个slab是有一个或者多个连续的页组成
kmalloc是基于slab分配器的
利用cat /porc/slabinfo来打印出相关的结构
1 | Boot took 0.99 seconds |
active_objs 正在被使用的obj的数量
num_objs obj的总量
objsize obj的大小
objperslab 每个slab中可以有多少个obj
pagesperslab 每个slab对应几个页·
slab allocator
buddy系统会产生大量的内碎片,比如(伙伴系统只能分配连续的物理内存页)一个33page的请求就伙伴系统就会分配2^6=64pages,相当于浪费了31pages。引入slab allocator就是为了把页分成更小的块来进行分配。
slab 核心思想是在保存那些常用堆块的缓存,以便能够在内核中进行分配。这是非常有意义的,通过缓存被释放obj,有一些常用的结构就能够在复制新的同样的结构时进行快速分配。通过重新利用被释放的obj,在某些情况下,内核就不必再重新申请内存了。Linux的slab allocator经过长期的发展,已经发生了很大的变化。现在slab allocator有三种不同的实现
- SLOB Allocator 是在solaris os被实现的最原始的slab allocator,现在大多被用在内存很小的嵌入式系统里,分配小内存非常高效,首次适应分配算法
- SLAB Allocator SLAB的升级,旨在变得更加的“cache friendly”
- SLUB Allocator 通过减少使用的队列/链来回获得比SLAB更好的执行时间
今天大多数系统中使用的SLUB
一个slab cache包含许多slab,一个slab中包含很多obj
?分别对应什么结构
slab cahes —>struct kmem_cache
页 —> struct page
slab —> page
obj的结构
有两种主要的cache
- Dedicate(专用的):这些缓存是给那些常用的内核中的结构的。这写结构被分配时就是初始化过的,被释放的时候还是保持被初始化的,一边下一次分配的时候会变得更快
- Generic(通用的):这些都是通用的缓存,在大多数情况下,它们的大小对应于2的幂。
dma-kmalloc-256 以上时专用缓存,dma-kmalloc-256及以下时通用缓存。
1 | vm_area_struct 65543 66082 208 19 1 : tunables 0 0 0 : slabdata 3478 3478 0 |
kmalloc
kmalloc是内核通过slab allocator进行一般内存分配的接口
1 | // "include/linux/slab.h" |
专用缓存(Dedicated Cache)的初始化
以vm_area_struct的slab cache 为例子
1 | //"kernel/fork.c" |
SLAB Cache 管理
kmem_cache中的结构
unsigned int gfporder
每个slab能够存放的页的数量。
struct kmem_cache_node *node[MAN_NUMNODES]
用来存储不同状态的slab,主要维护三个变量,这个主要是维护这个kmem_cache_node中的slab的信息。
1 | /* |
struct array_cache __percpu *cpu_cache
这个结构是管理被释放的obj的块,entry中的每一项指向被释放的对象。
1 | /* |
page中的void s_mem指向slab中的第一个obj;void freelist;指向第一个free的obj
1 | struct { /* slab, slob and slub */ |
SLUB
用来管理被释放的obj
1 | struct kmem_cache_cpu { |