swap用来做什么
缓存和缓冲区属于可回收内存,它们在内存管理中,通常被叫做文件页(File- backed page)大部分文件页都可以直接回收,以后需要时,再从磁盘重新读取就可以了,那些被应用程序修改过,并且暂时没有写入磁盘的数据(脏页)就得先写入磁盘,然后才能进行内存释放
除了文件页外,应用程序动态分配的堆内存叫做匿名页(Anonymous Page)如堆,栈,数据段等,不是以文件形式存在,因此无法和磁盘文件交换,是通过swap机制把不常访问匿名页占用的内存写入到磁盘中,然后释放这些内存,再次方式这些内存时,重新冲磁盘写入内存就可以了
匿名页 和 文件页 的回收都是基于LRU算法,优先回收不常访问的内存,所以LRU维护了active和inactive两个双向链表
- active:记录活跃内存页
- inactive:记录不活跃内存页
活跃和非活跃的 匿名页 和 文件页 大小查看
cat /proc/meminfo | grep -i active | sort
Active: 274616 kB
Active(anon): 38224 kB
Active(file): 236392 kB
Inactive: 320624 kB
Inactive(anon): 136 kB
Inactive(file): 320488 kB
swap 原理
Swap就是把一块磁盘空间或者本地文件想做内存来使用,它包括换出和换入两个过程
- 换出:就是把进程暂时不用的内存数据存储到磁盘中,并且释放这些数据占用的内存
- 换入:进程再次访问这些内存的时候,把它们从磁盘读取到内存中
使用场景
Swap其实就是把系统的可用内存变大了,即使服务器内存不足,页可用运行大内存的应用程序
- 内存不足时,有些程序并不想被OOM杀死,而是希望能缓一段时间,等待人工介入或者等系统自动释放其他进程的内容,再分配给它就会用到swap
swap也是为了回收匿名页占用的内存
直接内存回收:当有大块内存分配请求,但是内存不足,这时候系统就会回收一部分内存(比如缓存)尽可能的满足新内存的请求,这个过程叫做 直接内存回收
定时内存回收:内核kswapd0线程用来定时回收内存,为了衡量内存的使用情况,kswapd0定义了三个内存阈值是 页最小阈值(pages_min),页低阈值(pages_low)和页高阈值(pages_high),剩余内存则使用pages_free表示
- 剩余内存 < 页最小阈值:说明内存可用内存都耗尽了,只有内核才可以分配内存
- 剩余内存落在页最小阈值和页低阈值中间:说明内存使用比较大,剩余内存不多了,kswapd0回执行内存回收,知道剩余内存大于高阈值为止
- 剩余内存落在页低阈值和页高阈值中间:说明内存有一定压力,但是还可以满足新内存请求。
- 剩余内存 > 页高阈值:说明剩余内存比较对,没有内存压力
页低赋值可以通过内核选项vm.min_free_kbytes
间接设置 /proc/sys/vm/min_free_kbytes,min_free_kbytes设置了页最小阈值,其他两个阈值根据页最小阈值计算生成的
pages_low = pages_min*5/4
pages_high = pages_min*3/2
NUMA与Swap
有时候系统内存剩余还很多,但是Swap还是升高了,是因为处理器NUMA架构导致的
在NUMA框架下,多个处理器被划分到不同Node上,且每个Node 都拥有自己的本地内存空间,并且进一步又分为内内参域(zone),不如 直接内存访问区(DMA),普通内存区(NORMAL),伪内存区(MOVABLE)等
因为NUMA框架下每个Node都有自己的本地内存空间,所以分析内存使用需要根据每个Node单独分析, 可以通过numactl 查看每个Node内存使用情况
[root@master1 ~]# numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3
node 0 size: 8191 MB
node 0 free: 1793 MB
node distances:
node 0
0: 10
根据这个输出,我们系统中只有一个Node,就是Node0,编号为0 1 2 3的CPU都位于Node0上。另外Node0的内存大小为 8191 MB,剩余1793 MB
前面提到的页最小,页低,页高的三个阈值都可以在内存域/proc/zoneinfo来查看
[root@master1 ~]# cat /proc/zoneinfo | grep -i -A 15 "Node 0"
Node 0, zone DMA
pages free 3975
min 30
low 37
high 45
scanned 0
spanned 4095
present 3998
managed 3977
nr_free_pages 3975
nr_alloc_batch 8
nr_inactive_anon 0
nr_active_anon 0
nr_inactive_file 0
nr_active_file 0
nr_unevictable 0
--
Node 0, zone DMA32
pages free 159434
min 5530
low 6912
high 8295
scanned 0
spanned 1044480
present 782327
managed 721081
nr_free_pages 159434
nr_alloc_batch 1343
nr_inactive_anon 14605
nr_active_anon 95179
nr_inactive_file 193717
nr_active_file 206850
nr_unevictable 0
--
Node 0, zone Normal
pages free 295068
min 9798
low 12247
high 14697
scanned 0
spanned 1310720
present 1310720
managed 1277513
nr_free_pages 295068
nr_alloc_batch 127
nr_inactive_anon 16505
nr_active_anon 141332
nr_inactive_file 335925
nr_active_file 383442
nr_unevictable 0
上面输出包含了三个内存域的指标,min,low,high 就是上面提到的三个内存阈值,而free是剩余内存页数它跟后面的nr_free_pages相同 注意: 这里单位是页,每一页是4kb,比如计算页最小阈值需要把 三个zone的min相加 * 4kb(9798 + 5530 + 30)* 4
根据输入内容发现pages free剩余内存远高于high,所以此时kswapd0不会回收内存,当某个Node内存不足时,系统可以从其他Node寻找空闲内容,页可以从本地内存中回收内存,需要选哪个模式,可以通过/proc/sys/vm/zone_reclaim_mode来调整
- 默认为0,也就是刚刚提到的模式,表示既可以从其他Node寻找空闲内,页可以从本地回收内存,这时候就会导致回收文件页和匿名页,匿名页的回收所以会触发swap
- 1,2,4,表示只回收本地内存,2表示可以回收写脏数据回收内存,4表示可以用Swap方式回收内存
swappiness
使用swap的积极程度可以通过内核参数 vm.swappiness 间接配置 /proc/sys/vm/swappiness 选项,配置范围0-100,数字越大,越积极使用Swap,也就是更倾向于回收匿名页,数值越小,越消极使用Swap
即使你设置为0,当剩余内存文件页小于高阈值时,还是会发生Swap
# 按VmSwap使用量对进程排序,输出进程名称、进程ID以及SWAP用量
$ for file in /proc/*/status ; do awk '/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 3 -n -r | head
dockerd 2226 10728 kB
docker-containe 2251 8516 kB
snapd 936 4020 kB
networkd-dispat 911 836 kB
polkitd 1004 44 kB
总结
Linux通过直接内存回收和定时内存扫描回收方式来释放文件页和匿名页
- 文件页的回收:就是直接回收缓存,或者把脏数据写回磁盘后释放
- 匿名也的回收:需要通过Swap换出到磁盘中,下次访问时,在从磁盘换入到内存中
定时内存扫描回收方式的阈值可以通过内核选项vm.min_free_kbytes
来设置
只要涉及到回收匿名页就会涉及触发Swap
假如没有开启swap的话,进程的匿名页就无法释放,需要在进程的重启或者杀掉释放
swap使用积极程度可以通过内核参数vm.swappiness 设置
在处理器NUMA框架下,每个Node都有自己的内存域,某个Node自己内存域下剩余内存不多情况下,导致内存回收也就有可能触发Swap