Linux内存之Slab

Linux内存管理模式,页式管理适合于大块内存的情形,而对于内核对象级别的较小内存情形下,不足以占用1个页。

在linux内核中会有许多小对象,这些对象构造销毁十分频繁,比如i-node,dentry。这么这些对象如果每次构建的时候就向内存要一个页,而其实际大小可能只有几个字节,这样就非常浪费,为了解决这个问题就引入了一种新的机制来处理在同一页框中如何分配小存储器区。这就是我们要讨论的slab层。在讲述slab前,我想先铺垫一下有关内存页的概念,我们都知道在linux中内存都是以页为单位来进行管理的(通常为4KB),当内核需要内存就调用如:kmem_getpages这样的接口(底层调用__alloc_pages())。那么内核是如何管理页的分配的,这里linux使用了伙伴算法。slab也是向内核申请一个个页,然后再对这些页框做管理来达到分配小存储区的目的的。

什么是Slab呢?

最早于1994年在Sun系统中被提出(The Slab Allocator: An Object-Caching Kernel Memory Allocator, Jeff Bonwick (Sun Microsystems)),Slab是一种内存分配器,通过将内存划分不同大小的空间分配给对象使用来进行缓存管理,应用于内核对象的缓存。

A slab is a set of one or more contiguous pages of memory set aside by the slab allocator for an individual cache. This memory is further divided into equal segments the size of the object type that the cache is managing.

Slab的两个主要作用:

  • Slab对小对象进行分配,不用为每个小对象分配一个页,节省了空间。
  • 内核中一些小对象创建析构很频繁,Slab对这些小对象做缓存,可以重复利用一些相同的对象,减少内存分配次数。

    /proc/meminfo的Slab和SReclaimable项

    其中Slab=SReclaimable+SUnreclaimSReclaimable表示可回收使用的内存。
    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
    # cat /proc/meminfo
    MemTotal: 15993324 kB
    MemFree: 178448 kB
    MemAvailable: 14670236 kB
    Buffers: 166740 kB
    Cached: 3704632 kB
    SwapCached: 0 kB
    Active: 3337344 kB
    Inactive: 1151668 kB
    Active(anon): 717392 kB
    Inactive(anon): 116980 kB
    Active(file): 2619952 kB
    Inactive(file): 1034688 kB
    Unevictable: 0 kB
    Mlocked: 0 kB
    SwapTotal: 0 kB
    SwapFree: 0 kB
    Dirty: 236 kB
    Writeback: 0 kB
    AnonPages: 617560 kB
    Mapped: 84988 kB
    Shmem: 216732 kB
    Slab: 11165136 kB // Slab总量
    SReclaimable: 11090552 kB // 可回收Slab量
    SUnreclaim: 74584 kB
    .............. // 其他信息省略

命令slabtop查看slab占用情况

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# slabtop
Active / Total Objects (% used) : 131433 / 135261 (97.2%)
Active / Total Slabs (% used) : 5390 / 5390 (100.0%)
Active / Total Caches (% used) : 63 / 87 (72.4%)
Active / Total Size (% used) : 28769.26K / 30102.88K (95.6%)
Minimum / Average / Maximum Object : 0.01K / 0.22K / 8.00K

OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
23616 23616 100% 0.21K 1312 18 5248K vm_area_struct
22080 21832 98% 0.06K 345 64 1380K kmalloc-64
12831 12080 94% 0.19K 611 21 2444K dentry
10044 10044 100% 0.11K 279 36 1116K sysfs_dir_cache
8109 7568 93% 0.08K 159 51 636K selinux_inode_security
7936 7936 100% 0.06K 124 64 496K anon_vma
7722 7722 100% 0.10K 198 39 792K buffer_head
6110 5759 94% 0.58K 470 13 3760K inode_cache
4732 4694 99% 0.57K 338 14 2704K radix_tree_node
3072 3072 100% 0.01K 6 512 24K kmalloc-8
3072 3056 99% 0.96K 384 8 3072K ext4_inode_cache
2848 2574 90% 0.25K 178 16 712K kmalloc-256
2380 2380 100% 0.05K 28 85 112K shared_policy_node
2048 2048 100% 0.02K 8 256 32K kmalloc-16
2040 1530 75% 0.04K 20 102 80K jbd2_journal_handle
2016 1615 80% 0.19K 96 21 384K kmalloc-192
1776 1776 100% 0.64K 148 12 1184K proc_inode_cache
1288 1288 100% 0.07K 23 56 92K Acpi-ParseExt
1152 1152 100% 0.03K 9 128 36K kmalloc-32
1152 832 72% 0.06K 18 64 72K ext4_io_end
1140 1140 100% 0.66K 95 12 760K shmem_inode_cache
1072 1053 98% 1.00K 134 8 1072K kmalloc-1024
960 960 100% 0.12K 30 32 120K kmalloc-128
672 672 100% 0.09K 16 42 64K kmalloc-96
432 394 91% 0.50K 54 8 216K kmalloc-512
408 408 100% 0.04K 4 102 16K Acpi-Namespace
408 324 79% 0.62K 34 12 272K sock_inode_cache
352 243 69% 2.00K 44 8 704K kmalloc-2048
340 340 100% 0.12K 10 34 40K fsnotify_event
256 256 100% 0.03K 2 128 8K jbd2_revoke_record_s
256 256 100% 0.02K 1 256 4K jbd2_revoke_table_s
224 224 100% 0.25K 14 16 56K tw_sock_TCP
208 208 100% 0.94K 26 8 208K RAW
190 190 100% 0.81K 10 19 160K task_xstate
187 154 82% 2.84K 17 11 544K task_struct
180 180 100% 0.38K 18 10 72K blkdev_requests
180 180 100% 0.11K 5 36 20K jbd2_journal_head
180 180 100% 0.13K 6 30 24K ext4_allocation_context
154 139 90% 1.12K 11 14 176K signal_cache
150 150 100% 2.06K 10 15 320K idr_layer_cache
150 143 95% 2.06K 10 15 320K sighand_cache
128 128 100% 0.06K 2 64 8K kmem_cache_node
117 117 100% 0.10K 3 39 12K blkdev_ioc
112 102 91% 4.00K 14 8 448K kmalloc-4096
110 101 91% 1.56K 11 10 176K mm_struct
108 108 100% 0.62K 9 12 72K files_cache
96 96 100% 0.25K 6 16 24K kmem_cache
96 62 64% 1.88K 12 8 192K TCP
73 73 100% 0.05K 1 73 4K ip_fib_trie
64 64 100% 0.25K 4 16 16K dquot
46 46 100% 0.09K 1 46 4K ext4_xattr
40 20 50% 8.00K 10 4 320K kmalloc-8192
25 25 100% 0.16K 1 25 4K sigqueue
19 19 100% 0.81K 1 19 16K bdev_cache
16 16 100% 1.88K 2 8 32K blkdev_queue
15 15 100% 0.26K 1 15 4K numa_policy

系统缓存回收机制的设置项

系统默认内存回收配置在/proc/sys/vm/drop_caches中,除非明确知晓改动对系统全局影响,不建议对此进行修改。

0:不做任何处理,由系统自己管理 1:清空pagecache 2:清空dentries和inodes 3:清空pagecache、dentries和inodes

1
2
# cat /proc/sys/vm/drop_caches
0

/proc/slabinfo文件信息

在Slab中,可分配内存块称为对象,下图中kmalloc-8表示每个对象占用8Bit大小的普通Slab,同理kmalloc-16中每个对象占用16B,依次类推,找出Slab中占用量较大的对象是哪些?

每种对象占用总内存量 = num_objs*objsize

列出几种对象的内存空间占有量:

名称 对象数量 每个对象大小(B) 该类型所有对象总量(B)
ext4_inode_cache 6168 984 6069312
ext4_inode_cache 6168 984 6069312
  • 统计Slab占用超过100M的对象:
    1
    # cat /proc/slabinfo |awk '{if($3*$4/1024/1024 > 100){print $1,$3*$4/1024/1024} }'
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
sudo 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>
ext4_inode_cache 1560 6168 984 8 2 : tunables 0 0 0 : slabdata 771 771 0
ext4_xattr 46 46 88 46 1 : tunables 0 0 0 : slabdata 1 1 0
ext4_allocation_context 180 180 136 30 1 : tunables 0 0 0 : slabdata 6 6 0
ext4_io_end 1920 2240 64 64 1 : tunables 0 0 0 : slabdata 35 35 0
jbd2_journal_handle 2448 2448 40 102 1 : tunables 0 0 0 : slabdata 24 24 0
jbd2_journal_head 468 468 112 36 1 : tunables 0 0 0 : slabdata 13 13 0
jbd2_revoke_table_s 256 256 16 256 1 : tunables 0 0 0 : slabdata 1 1 0
jbd2_revoke_record_s 384 384 32 128 1 : tunables 0 0 0 : slabdata 3 3 0
scsi_cmd_cache 9 9 448 9 1 : tunables 0 0 0 : slabdata 1 1 0
UDPLITEv6 0 0 1152 14 4 : tunables 0 0 0 : slabdata 0 0 0
UDPv6 14 14 1152 14 4 : tunables 0 0 0 : slabdata 1 1 0
tw_sock_TCPv6 0 0 256 16 1 : tunables 0 0 0 : slabdata 0 0 0
TCPv6 8 8 2048 8 4 : tunables 0 0 0 : slabdata 1 1 0
cfq_queue 0 0 232 17 1 : tunables 0 0 0 : slabdata 0 0 0
bsg_cmd 0 0 312 13 1 : tunables 0 0 0 : slabdata 0 0 0
mqueue_inode_cache 9 9 896 9 2 : tunables 0 0 0 : slabdata 1 1 0
hugetlbfs_inode_cache 13 13 608 13 2 : tunables 0 0 0 : slabdata 1 1 0
configfs_dir_cache 46 46 88 46 1 : tunables 0 0 0 : slabdata 1 1 0
dquot 64 64 256 16 1 : tunables 0 0 0 : slabdata 4 4 0
pid_namespace 0 0 2176 15 8 : tunables 0 0 0 : slabdata 0 0 0
posix_timers_cache 0 0 248 16 1 : tunables 0 0 0 : slabdata 0 0 0
UDP-Lite 0 0 1024 8 2 : tunables 0 0 0 : slabdata 0 0 0
ip_fib_trie 73 73 56 73 1 : tunables 0 0 0 : slabdata 1 1 0
RAW 208 208 960 8 2 : tunables 0 0 0 : slabdata 26 26 0
UDP 8 8 1024 8 2 : tunables 0 0 0 : slabdata 1 1 0
tw_sock_TCP 224 224 256 16 1 : tunables 0 0 0 : slabdata 14 14 0
TCP 61 96 1920 8 4 : tunables 0 0 0 : slabdata 12 12 0
blkdev_queue 16 16 1920 8 4 : tunables 0 0 0 : slabdata 2 2 0
blkdev_requests 160 160 384 10 1 : tunables 0 0 0 : slabdata 16 16 0
blkdev_ioc 117 117 104 39 1 : tunables 0 0 0 : slabdata 3 3 0
fsnotify_event_holder 0 0 24 170 1 : tunables 0 0 0 : slabdata 0 0 0
fsnotify_event 914 952 120 34 1 : tunables 0 0 0 : slabdata 28 28 0
sock_inode_cache 321 408 640 12 2 : tunables 0 0 0 : slabdata 34 34 0
net_namespace 0 0 4224 7 8 : tunables 0 0 0 : slabdata 0 0 0
shmem_inode_cache 1090 1128 680 12 2 : tunables 0 0 0 : slabdata 94 94 0
Acpi-ParseExt 1288 1288 72 56 1 : tunables 0 0 0 : slabdata 23 23 0
Acpi-Namespace 408 408 40 102 1 : tunables 0 0 0 : slabdata 4 4 0
taskstats 24 24 328 12 1 : tunables 0 0 0 : slabdata 2 2 0
proc_inode_cache 1584 1584 656 12 2 : tunables 0 0 0 : slabdata 132 132 0
sigqueue 25 25 160 25 1 : tunables 0 0 0 : slabdata 1 1 0
bdev_cache 19 19 832 19 4 : tunables 0 0 0 : slabdata 1 1 0
sysfs_dir_cache 10044 10044 112 36 1 : tunables 0 0 0 : slabdata 279 279 0
inode_cache 5778 6175 592 13 2 : tunables 0 0 0 : slabdata 475 475 0
dentry 9326 13986 192 21 1 : tunables 0 0 0 : slabdata 666 666 0
iint_cache 0 0 80 51 1 : tunables 0 0 0 : slabdata 0 0 0
selinux_inode_security 7568 8109 80 51 1 : tunables 0 0 0 : slabdata 159 159 0
buffer_head 2293 10998 104 39 1 : tunables 0 0 0 : slabdata 282 282 0
vm_area_struct 21510 21510 216 18 1 : tunables 0 0 0 : slabdata 1195 1195 0
mm_struct 85 120 1600 10 4 : tunables 0 0 0 : slabdata 12 12 0
files_cache 108 108 640 12 2 : tunables 0 0 0 : slabdata 9 9 0
signal_cache 135 168 1152 14 4 : tunables 0 0 0 : slabdata 12 12 0
sighand_cache 131 150 2112 15 8 : tunables 0 0 0 : slabdata 10 10 0
task_xstate 190 190 832 19 4 : tunables 0 0 0 : slabdata 10 10 0
task_struct 153 187 2912 11 8 : tunables 0 0 0 : slabdata 17 17 0
anon_vma 7108 7168 64 64 1 : tunables 0 0 0 : slabdata 112 112 0
shared_policy_node 3914 4335 48 85 1 : tunables 0 0 0 : slabdata 51 51 0
numa_policy 15 15 264 15 1 : tunables 0 0 0 : slabdata 1 1 0
radix_tree_node 5399 8288 584 14 2 : tunables 0 0 0 : slabdata 592 592 0
idr_layer_cache 150 150 2112 15 8 : tunables 0 0 0 : slabdata 10 10 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 8 4 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-1024 0 0 1024 8 2 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-512 0 0 512 8 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-256 0 0 256 16 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-128 0 0 128 32 1 : 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 21 1 : 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 20 40 8192 4 8 : tunables 0 0 0 : slabdata 10 10 0
kmalloc-4096 92 112 4096 8 8 : tunables 0 0 0 : slabdata 14 14 0
kmalloc-2048 216 240 2048 8 4 : tunables 0 0 0 : slabdata 30 30 0
kmalloc-1024 976 992 1024 8 2 : tunables 0 0 0 : slabdata 124 124 0
kmalloc-512 334 376 512 8 1 : tunables 0 0 0 : slabdata 47 47 0
kmalloc-256 2185 2592 256 16 1 : tunables 0 0 0 : slabdata 162 162 0
kmalloc-192 1324 1764 192 21 1 : tunables 0 0 0 : slabdata 84 84 0
kmalloc-128 992 992 128 32 1 : tunables 0 0 0 : slabdata 31 31 0
kmalloc-96 756 756 96 42 1 : tunables 0 0 0 : slabdata 18 18 0
kmalloc-64 19961 21248 64 64 1 : tunables 0 0 0 : slabdata 332 332 0
kmalloc-32 1792 1792 32 128 1 : tunables 0 0 0 : slabdata 14 14 0
kmalloc-16 2048 2048 16 256 1 : tunables 0 0 0 : slabdata 8 8 0
kmalloc-8 3072 3072 8 512 1 : tunables 0 0 0 : slabdata 6 6 0
kmem_cache_node 128 128 64 64 1 : tunables 0 0 0 : slabdata 2 2 0
kmem_cache 96 96 256 16 1 : tunables 0 0 0 : slabdata 6 6 0

总结

上述简要概述了内核Slab内存分配器的作用、意义,如何在Linux中查询、分析当前系统的Slab内存占用情况,从而合理评估系统内存的可用资源。

参考