Linux内存管理之slab 2:slab API
https://blog.csdn.net/lqy971966/article/details/119801912
1. 为什么有了Buddy(伙伴系统)还需要slab?
1.1 什么是伙伴系统?
Linux内核中使用伙伴系统(buddy system)算法以页为单位管理内存,进行内存分配。
1.1.1 伙伴系统思想
它把所有的空闲页放到11个链表中,每个链表分别管理大小为1,2,4,8,16,32,64,128,256,512,1024个页的内存块。当系统需要分配内存时,就可以从buddy系统中获取。
1.2 伙伴系统例子说明
例如,要申请一块包含4个页的连续内存,就直接从buddy系统中管理4个页连续内存的链表中获取。同样的,如果系统需要申请3个页的连续内存,则只能在4个页的链表中获取,剩下的一个页被放到buddy系统中管理1个页的链表中。
1.3 伙伴系统能解决的问题
Buddy 系统解决了物理内存分配的外部碎片问题。
Linux内存管理 - buddy系统
https://www.cnblogs.com/longchang/p/10749392.html
2 为什么需要引入slab算法?
2.1 伙伴系统的缺点
Buddy提供了以page为单位的内存分配接口,这对内核来说颗粒度还太大了,所以需要一种新的机制,将page拆分为更小的单位来管理。
2.2 伙伴系统的缺点例子说明
Linux内存以页为单位进行内存管理,buddy算法以2的n次方个页面来进行内存分配管理,最小为20,也就是一页,最大为211,就是4MB大小的连续内存空间。但是页的粒度还是太大,Linux下是4KB大小,也就是4096个字节,而kernel本身有很多数据结构时时刻刻都需要分配或者释放,这些数据的大小又往往小于4KB大小,一般只有几个几十个字节这样的大小。
比方最常用到的task_struct(进程描述符)结构体和mm_struct(内存描述符)结构体,其中,izeof task_struct = 9152,sizeof mm_struct = 2064。
task_struct稍微大一点将近2个页面,mm_struct就只有差不多半个页面了。这样一来如果所有的这些数据结构都按照页来分配存储和管理,那么我相信kernel过不了多久自己就玩完了,内存碎片肯定一堆一堆。
所以,引入slab分配器是为了弥补内存管理粒度太大的不足。
3. slab 能解决什么问题?
slab分配需要解决的是内存的内部碎片问题。
所谓内部碎片就是指被内核分配出去但是不能被利用的内存。
而外部碎片是指由于频繁地申请和释放页框而导致的某些小的连续页框,比方只有一个页框,无法分配给需要大的连续页框的进程而导致的内存碎片。
3.3 slab 分配例子
比如我需要一个100字节的连续物理内存,那么内核slab分配器会给我提供一个相应大小的连续物理内存单元,为128字节大小(不会是整好100字节,而是这个档的一个对齐值,如100字节对应128字节,30字节对应32字节,60字节对应64字节)
4. slab系统核心思想是什么?
4.0. 须知:
kmem_cache: 内存池
slab: 内存池从系统申请内存的基本单位
object: 内存池提供的内存的单位
123
4.1 slab核心思想:对象管理内存(简单说:就是你经常用什么我先给你创造一堆出来,你要用直接拿,不用放回来)
使用对象的概念来管理内存。
slab分配器的基本思想是,先利用页面分配器分配出单个或者一组连续的物理页面,然后在此基础上将整块页面分割成多个相等的小内存单元,以满足小内存空间分配的需要。当然,为了有效的管理这些小的内存单元并保证极高的内存使用速度和效率。
这段话摘自:《深入linux设备驱动程序内核机制》
https://blog.csdn.net/yuzhihui_no1/article/details/47305361
4.2 slab的对象/内存池思想
在内核中,经常会使用一些链表,链表中会申请许多相同结构的结构体,比如文件对象,进程对象等等,如果申请比较频繁,那么为它们建立一个内存池,内存池中都是相同结构的结构体,当想申请这种结构体时,直接从这种内存池中取一个结构体出来,是有用且速度极快的。一个物理页就可以作用这种内存池的载体,进而进行充分利用,减少了内部碎片的产生。
所以,Slab 相当于内存池思想,且是为了解决内碎片而产生的,slab的核心思想是以对象的观点管理内存。
4.3 slab中对象是什么?
所谓的对象就是存放一组数据结构的内存区,为便于理解可把对象看作内核中的数据结构(例如:task_struct,file_struct 等)。
相同类型的对象归为一类,每当要申请这样一个对象时,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免内部碎片。
4.4 cache是内存中的区域,而不是指硬件高速缓存
这种场景是非常多的,为了应对这种场景,slab为这样的对象创建一个cache,即缓存。每个cache所占的内存区又被划分多个slab,每个 slab是由一个或多个连续的页框组成。每个页框中包含若干个对象,既有已经分配的对象,也包含空闲的对象。
尽管英文中使用了Cache这个词,但实际上指的是内存中的区域,而不是指硬件高速缓存
4.5 lab分配器的一个基本原则
slab分配器对不同长度内存是分档的,这是slab分配器的一个基本原则,按申请的内存的大小分配相应长度的内存。
这可以先参考kmalloc的实现,kmalloc申请的物理内存长度为参数size,它需要先根据这个长度找到相应的长度的缓存
slab分配器并非一开始就能智能的根据内存分档值分配相应长度的内存。每种cache对应一种长度的slab分配。
5 slab分配的最小和最大内存单元是多少?
23、………211个字节。
另外还有两个特殊的组,分别是96B和192B,共11组
所以,slab分配内存大小是:
8B,16B,32B,64B,96B,128B,192B,256B,512B,1024B,2048B等大小。共11组
5.1 cat /proc/slabinfo 查看系统中的slab对象
[root@localhost 10]# cat /proc/slabinfo
slabinfo - version: 2.1
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
rpc_inode_cache 51 51 640 51 8 : tunables 0 0 0 : slabdata 1 1 0
xfs_dqtrx 0 0 528 62 8 : tunables 0 0 0 : slabdata 0 0 0
xfs_dquot 0 0 488 67 8 : tunables 0 0 0 : slabdata 0 0 0
xfs_ili 2160 2160 168 48 2 : tunables 0 0 0 : slabdata 45 45 0
xfs_inode 21352 21352 960 34 8 : tunables 0 0 0 : slabdata 628 628 0
xfs_efd_item 156 156 416 39 4 : tunables 0 0 0 : slabdata 4 4 0
xfs_btree_cur 39 39 208 39 2 : tunables 0 0 0 : slabdata 1 1 0
xfs_log_ticket 44 44 184 44 2 : tunables 0 0 0 : slabdata 1 1 0
bio-2 51 51 320 51 4 : tunables 0 0 0 : slabdata 1 1 0
kcopyd_job 0 0 3312 9 8 : tunables 0 0 0 : slabdata 0 0 0
dm_uevent 0 0 2608 12 8 : tunables 0 0 0 : slabdata 0 0 0
dm_rq_target_io 0 0 136 60 2 : tunables 0 0 0 : slabdata 0 0 0
ip6_dst_cache 72 72 448 36 4 : tunables 0 0 0 : slabdata 2 2 0
RAWv6 286 286 1216 26 8 : tunables 0 0 0 : slabdata 11 11 0
UDPLITEv6 0 0 1216 26 8 : tunables 0 0 0 : slabdata 0 0 0
UDPv6 26 26 1216 26 8 : tunables 0 0 0 : slabdata 1 1 0
tw_sock_TCPv6 0 0 256 64 4 : tunables 0 0 0 : slabdata 0 0 0
TCPv6 15 15 2176 15 8 : tunables 0 0 0 : slabdata 1 1 0
cfq_queue 70 70 232 70 4 : tunables 0 0 0 : slabdata 1 1 0
bsg_cmd 0 0 312 52 4 : tunables 0 0 0 : slabdata 0 0 0
mqueue_inode_cache 36 36 896 36 8 : tunables 0 0 0 : slabdata 1 1 0
hugetlbfs_inode_cache 53 53 608 53 8 : tunables 0 0 0 : slabdata 1 1 0
configfs_dir_cache 0 0 88 46 1 : tunables 0 0 0 : slabdata 0 0 0
dquot 0 0 256 64 4 : tunables 0 0 0 : slabdata 0 0 0
userfaultfd_ctx_cache 0 0 192 42 2 : tunables 0 0 0 : slabdata 0 0 0
fanotify_event_info 73 73 56 73 1 : tunables 0 0 0 : slabdata 1 1 0
pid_namespace 0 0 2200 14 8 : tunables 0 0 0 : slabdata 0 0 0
posix_timers_cache 66 66 248 66 4 : tunables 0 0 0 : slabdata 1 1 0
UDP-Lite 0 0 1088 30 8 : tunables 0 0 0 : slabdata 0 0 0
flow_cache 0 0 144 56 2 : tunables 0 0 0 : slabdata 0 0 0
xfrm_dst_cache 0 0 576 56 8 : tunables 0 0 0 : slabdata 0 0 0
UDP 30 30 1088 30 8 : tunables 0 0 0 : slabdata 1 1 0
tw_sock_TCP 0 0 256 64 4 : tunables 0 0 0 : slabdata 0 0 0
TCP 16 16 1984 16 8 : tunables 0 0 0 : slabdata 1 1 0
dax_cache 42 42 768 42 8 : tunables 0 0 0 : slabdata 1 1 0
blkdev_queue 26 26 2424 13 8 : tunables 0 0 0 : slabdata 2 2 0
blkdev_ioc 78 78 104 39 1 : tunables 0 0 0 : slabdata 2 2 0
user_namespace 68 68 480 68 8 : tunables 0 0 0 : slabdata 1 1 0
dmaengine-unmap-128 30 30 1088 30 8 : tunables 0 0 0 : slabdata 1 1 0
sock_inode_cache 1020 1020 640 51 8 : tunables 0 0 0 : slabdata 20 20 0
fsnotify_mark_connector 129370 129370 24 170 1 : tunables 0 0 0 : slabdata 761 761 0
net_namespace 6 6 5248 6 8 : tunables 0 0 0 : slabdata 1 1 0
shmem_inode_cache 1200 1200 680 48 8 : tunables 0 0 0 : slabdata 25 25 0
Acpi-ParseExt 6440 6440 72 56 1 : tunables 0 0 0 : slabdata 115 115 0
Acpi-State 102 102 80 51 1 : tunables 0 0 0 : slabdata 2 2 0
task_delay_info 288 288 112 36 1 : tunables 0 0 0 : slabdata 8 8 0
taskstats 49 49 328 49 4 : tunables 0 0 0 : slabdata 1 1 0
proc_inode_cache 1621 1813 656 49 8 : tunables 0 0 0 : slabdata 37 37 0
sigqueue 51 51 160 51 2 : tunables 0 0 0 : slabdata 1 1 0
bdev_cache 39 39 832 39 8 : tunables 0 0 0 : slabdata 1 1 0
kernfs_node_cache 35360 35360 120 68 2 : tunables 0 0 0 : slabdata 520 520 0
mnt_cache 2478 2478 384 42 4 : tunables 0 0 0 : slabdata 59 59 0
inode_cache 16720 16720 592 55 8 : tunables 0 0 0 : slabdata 304 304 0
dentry 49350 49350 192 42 2 : tunables 0 0 0 : slabdata 1175 1175 0
iint_cache 0 0 128 64 2 : tunables 0 0 0 : slabdata 0 0 0
selinux_inode_security 45798 45798 40 102 1 : tunables 0 0 0 : slabdata 449 449 0
buffer_head 2145 2145 104 39 1 : tunables 0 0 0 : slabdata 55 55 0
vm_area_struct 4699 4699 216 37 2 : tunables 0 0 0 : slabdata 127 127 0
mm_struct 60 60 1600 20 8 : tunables 0 0 0 : slabdata 3 3 0
files_cache 204 204 640 51 8 : tunables 0 0 0 : slabdata 4 4 0
signal_cache 252 252 1152 28 8 : tunables 0 0 0 : slabdata 9 9 0
sighand_cache 255 255 2112 15 8 : tunables 0 0 0 : slabdata 17 17 0
task_xstate 273 273 832 39 8 : tunables 0 0 0 : slabdata 7 7 0
task_struct 255 264 4048 8 8 : tunables 0 0 0 : slabdata 33 33 0
anon_vma 1887 1887 80 51 1 : tunables 0 0 0 : slabdata 37 37 0
shared_policy_node 2635 2635 48 85 1 : tunables 0 0 0 : slabdata 31 31 0
numa_policy 186 186 264 62 4 : tunables 0 0 0 : slabdata 3 3 0
radix_tree_node 2856 2856 584 56 8 : tunables 0 0 0 : slabdata 51 51 0
idr_layer_cache 180 180 2112 15 8 : tunables 0 0 0 : slabdata 12 12 0
dma-kmalloc-8192 0 0 8192 4 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-4096 0 0 4096 8 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-2048 0 0 2048 16 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-1024 0 0 1024 32 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-512 64 64 512 64 8 : tunables 0 0 0 : slabdata 1 1 0
dma-kmalloc-256 0 0 256 64 4 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-128 0 0 128 64 2 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-64 0 0 64 64 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-32 0 0 32 128 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-16 0 0 16 256 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-8 0 0 8 512 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-192 0 0 192 42 2 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-96 0 0 96 42 1 : tunables 0 0 0 : slabdata 0 0 0
kmalloc-8192 40 40 8192 4 8 : tunables 0 0 0 : slabdata 10 10 0
kmalloc-4096 254 264 4096 8 8 : tunables 0 0 0 : slabdata 33 33 0
kmalloc-2048 955 1072 2048 16 8 : tunables 0 0 0 : slabdata 67 67 0
kmalloc-1024 2894 2976 1024 32 8 : tunables 0 0 0 : slabdata 93 93 0
kmalloc-512 4825 4864 512 64 8 : tunables 0 0 0 : slabdata 76 76 0
kmalloc-256 7406 7552 256 64 4 : tunables 0 0 0 : slabdata 118 118 0
kmalloc-192 7560 7560 192 42 2 : tunables 0 0 0 : slabdata 180 180 0
kmalloc-128 3136 3136 128 64 2 : tunables 0 0 0 : slabdata 49 49 0
kmalloc-96 5334 5334 96 42 1 : tunables 0 0 0 : slabdata 127 127 0
kmalloc-64 84850 85184 64 64 1 : tunables 0 0 0 : slabdata 1331 1331 0
kmalloc-32 125696 125696 32 128 1 : tunables 0 0 0 : slabdata 982 982 0
kmalloc-16 63232 63232 16 256 1 : tunables 0 0 0 : slabdata 247 247 0
kmalloc-8 86528 86528 8 512 1 : tunables 0 0 0 : slabdata 169 169 0
kmem_cache_node 128 128 64 64 1 : tunables 0 0 0 : slabdata 2 2 0
kmem_cache 128 128 256 64 4 : tunables 0 0 0 : slabdata 2 2 0
[root@localhost 10]#
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
6. slab与buddy系统的关系
6.1 互补的
slab系统与buddy系统所要解决的问题是互补的,一个解决外部碎片一个解决内部碎片,但事实上,slab在新建cache时同样需要用到buddy来为之分配页面,而在释放cache时也需要buddy来回收这此页面。也就是说,slab事实上是依赖buddy系统的。
6.2 实际还是伙伴系统分配物理页
从slab的分配可以知道,其实所有的内存最终还是要伙伴系统来分配,这里就可以知道,这些内存都是连续的物理页。
6.3 slab作为内核缓存对象
在某些情况下内核模块可能需要频繁的分配和释放相同的内存对象,这时候slab可以作为内核对象的缓存,当slab对象被释放时,slab分配器并不会把对象占用的物理空间还给伙伴系统。这样的好处是当内核模块需要再次分配内存对象时,不需要那么麻烦的向伙伴系统申请,而是可以直接在slab链表中分配一个合适的对象
7. slab 配器结构
7.1 slab 结构图
图:
解释:
每个kmem_cache都是链接在一起形成一个全局的双向链表,由cache指向该链表,系统可以从Cache_chain开始扫描每个kmem_cache,来找到一个大小最合适的kmem_cache,然后从该kmem_cache中分配一个对象
7.2 slab 结构解释
7.2.1 cache_chain
最高层是 cache_chain,这是一个 slab 缓存的链接列表。可以用来查找最适合所需要的分配大小的缓存(遍历列表)
cache_chain 的每个元素都是一个 kmem_cache 结构的引用(称为一个 cache)。它定义了一个要管理的给定大小的对象池。
7.2.2 kmem_cache
kmem_cache: 内存池
slab: 内存池从系统申请内存的基本单位
object: 内存池提供的内存的单位
123
7.2.2.1 kmem_cache 或 cache:
有的地方也会叫这个kmem_cache为cache,原因是kmem_cache中的object有大有小(其实也是kmem_cache有大有小),
当内存申请时,会有命中该kmem_cache的说法,和CPU中的cache命中是类似的意思,所以也会叫kmem_cache为cache
12
7.2.2.2 三条链表:slabs_full slabs_partial slabs_empty
每个缓存(kmem_cache)都包含了一个 slabs 列表,这是一段连续的内存块(通常都是页面)
其中每个kmem_cache有三条链表:
slabs_full 表示该链表中每个slab的object对象都已经分配完了
slabs_partial 表示该链表中的slab的object对象部分分配完了
slabs_empty 表示该链表中的object对象全部没有分配出去(空 slab,未分配)
123
对象的分配和释放都是在slab中进行的,所以slab可以在三条链表中移动,如果slab中的object都分配完了,则会移到full 链表中;如果分配了一部分object,则会移到partial链表中;如果所有object都释放了,则会移动到empty链表中;其中当系统内存紧张的时候,slabs_empty链表中的slab可能会被返回给系统。
7.2.2.3 cache_cache 结构体等说明
所有的kmem_cache结构都是从cache_cache分配的
static kmem_cache_t cache_cache = {
slabs_full: LIST_HEAD_INIT(cache_cache.slabs_full),
slabs_partial: LIST_HEAD_INIT(cache_cache.slabs_partial),
slabs_free: LIST_HEAD_INIT(cache_cache.slabs_free),
objsize: sizeof(kmem_cache_t),
flags: SLAB_NO_REAP,
spinlock: SPIN_LOCK_UNLOCKED,
colour_off: L1_CACHE_BYTES,
name: "kmem_cache",
};
struct cache_size{
size_t cs_size;
struct kmem_cache *cs_cachep;
}
struct cache_size malloc_sizes[] = {
{.cs_size = 32},
{.cs_size = 64},
{.cs_size = 128},
{.cs_size = 256},
................
{.cs_size = ~0UL},
};
12345678910111213141516171819202122232425
在系统初始化时,内核会调用kmem_cache_init函数对malloc_size数组进行遍历,对数组中的每个元素都调用kmem_cache_create()函数在cache_cache中分配一个struct kmem_cache 实例,并且把kmem_cache所在的地址赋值给cache_size中的cs_cachep指针
7.2.3 slab
slab 列表中的每个 slab 都是一个连续的内存块(一个或多个连续页),它们被划分成一个个对象(如 mm_struct)。
这些对象是从特定缓存中进行分配和释放的基本元素。
8. slab 和 /proc
proc 文件系统提供了一种简单的方法来监视系统中所有活动的 slab 缓存。
这个文件称为 /proc/slabinfo,
它除了提供一些可以从用户空间访问的可调整参数之外,还提供了有关所有 slab 缓存的详细信息。
如:
[root@localhost home]# cat /proc/slabinfo
slabinfo - version: 2.1
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
nf_conntrack_ffffffffb58fc900 51 51 320 51 4 : tunables 0 0 0 : slabdata 1 1 0
rpc_inode_cache 51 51 640 51 8 : tunables 0 0 0 : slabdata 1 1 0
xfs_dqtrx 0 0 528 62 8 : tunables 0 0 0 : slabdata 0 0 0
xfs_dquot 0 0 488 67 8 : tunables 0 0 0 : slabdata 0 0 0
xfs_ili 2016 2016 168 48 2 : tunables 0 0 0 : slabdata 42 42 0
xfs_inode 21182 21182 960 34 8 : tunables 0 0 0 : slabdata 623 623 0
xfs_efd_item 39 39 416 39 4 : tunables 0 0 0 : slabdata 1 1 0
xfs_btree_cur 39 39 208 39 2 : tunables 0 0 0 : slabdata 1 1 0
……
123456789101112
9. slab API
Linux内存管理之slab 2:slab API
https://blog.csdn.net/lqy971966/article/details/119801912
参考:
https://blog.csdn.net/yuzhihui_no1/article/details/47305361
参考:
https://blog.csdn.net/qq_22238021/article/details/80214759
https://zhuanlan.zhihu.com/p/61457076
https://blog.csdn.net/rockrockwu/article/details/79976833
https://www.cnblogs.com/wangzahngjun/p/4977425.html
原文链接:https://blog.csdn.net/lqy971966/article/details/112980005
标签:tunables,kmalloc,cache,内存,slabdata,slab,基本概念 From: https://www.cnblogs.com/dongxb/p/17922478.html