十九、为什么系统的Swap变高了?

一、什么是文件页?什么是脏页?什么是匿名页?

二、linux swap原理

换出

换入

三、内存回收的时机

1、直接内存回收

2、kswapd0内核线程

四、NUMA 与 Swap关系

五、swappiness

一、什么是文件页?什么是脏页?什么是匿名页?

1、缓存和缓冲区,就属于可回收内存。它们在内存管理中,通常被叫做 文件页(File-backed Page)

此外除了缓存和缓冲区,通过内存映射获取的文件映射页,也是一种常见的文件页。它也可以被释放掉,下次再访问的时候,从文件重新读取。

2、大部分文件页,都可以直接回收,以后有需要时,再从磁盘重新读取就可以了。而那些被应用程序修改过,并且暂时还没写入磁盘的数据(也就是 脏页 ),就得先写入磁盘,然后才能进行内存释放

脏页的写入磁盘的方式:

  • 系统调用 fsync ,把脏页同步到磁盘中
  • 也可以交给系统,由内核线程 pdflush 负责这些脏页的刷新

3、应用程序动态分配的堆内存称为 匿名页(Anonymous Page) 堆内存 很可能 还要再次被访问,当然不能直接回收了。非常正确,这些内存自然 不能直接释放

但是,如果这些内存在分配后很少被访问,似乎也是一种资源浪费。是不是可以把它们暂时先存在磁盘里,释放内存给其他更需要的进程?这就是Linux 的 Swap 机制。Swap 把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些内存时,重新从磁盘读入内存就可以了。

二、linux swap原理

Swap 把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些内存时,重新从磁盘读入内存就可以了。

换出

把进程 暂时不用的内存数据( 经过上文分析主要是堆内存 ) 存储到磁盘中,并释放这些数据占用的内存

换入

把进程 暂时不用的内存数据存储到磁盘 中,并释放这些数据占用的内存

给人的感觉是Swap 其实是把系统的可用内存变大了。这样,即使服务器的内存不足,也可以运行大内存的应用程序。其实在现在内存比较廉价的年代,对于追求高性能的业务完全可以关闭swap,因为内存和硬盘的速度在目前还存在瓶颈。

典型场景:

  1. 即使内存不足时,有些应用程序也并不想被 OOM 杀死,而是希望能缓一段时间,等待人工介入,或者等系统自动释放其他进程的内存,再分配给它。
  2. 我们常见的笔记本电脑的休眠和快速开机的功能,也基于 Swap 。休眠时,把系统的内存存入磁盘,这样等到再次开机时,只要从磁盘中加载内存就可以。这样就省去了很多应用程序的初始化过程,加快了开机速度

三、内存回收的时机

1、直接内存回收

有新的大块内存分配请求,但是剩余内存不足。这个时候系统就需要回收一部分内存(比如前面提到的缓存),进而尽可能地满足新内存请求。这个过程通常被称为 直接内存回收

2、kswapd0内核线程

除了直接内存回收,还有一个专门的内核线程用来定期回收内存,也就是kswapd0。

为了衡量内存的使用情况,kswapd0 定义了三个内存阈值(watermark,也称为水位)

  • 页最小阈值(pages_min)
  • 页低阈值(pages_low)
  • 页高阈值(pages_high)

剩余内存,则使用 pages_free 表。

十九、为什么系统的Swap变高了?

kswapd0 定期扫描 内存的使用情况,并根据剩余内存落在这三个阈值的空间位置,进行内存的回收操作

  • 剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存
  • 剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩余内存大于高阈值为止。
  • 剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求
  • 剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力。

一旦剩余内存小于 页低阈值 ,就会触发内存的回收。这个页低阈值,其实可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间接设置。 min_free_kbytes 设置了页最小阈值,而其他两个阈值,都是根据页最小阈值计算生成的,计算方法如下

pages_low = pages_min*5/4pages_high = pages_min*3/2

四、内存回收的方式

一旦发现内存紧张,系统会通过三种方式回收内存。这三种方式分别是 :

  • 基于 LRU(Least Recently Used)算法,回收缓存;
  • 基于 Swap 机制,回收不常访问的匿名页;
  • 基于 OOM(Out of Memory)机制,杀掉占用大量内存的进程

前两种方式,缓存回收和 Swap 回收,实际上都是基于 LRU 算法,也就是优先回收不常访问的内存。LRU 回收算法,实际上维护着 active 和 inactive 两个双向链表 ,其中:

  1. active 记录活跃的内存页;
  2. inactive 记录非活跃的内存页

越接近链表尾部,就表示内存页越不常访问。这样,在回收内存时,

系统就可以根据活跃程度, 优先回收不活跃的内存 。活跃和非活跃的内存页,按照类型的不同,又分别分为 文件页和匿名页 ,对应着 缓存回收和 Swap 回收

# grep 表示只保留包含 active 的指标(忽略大小写)# sort 表示按照字母顺序排序$ cat /proc/meminfo | grep -i active | sortActive(anon): 167976 kBActive(file): 971488 kBActive: 1139464 kBInactive(anon): 720 kBInactive(file): 2109536 kBInactive: 2110256 kB

第三种方式,OOM 机制按照 oom_score 给进程排序。oom_score 越大,进程就越容易被系统杀死

当系统发现内存不足以 分配新的内存请求时,就会尝试直接内存回收 。这种情况下,如果回收完文件页和匿名页后,内存够用了,当然皆大欢喜,把回收回来的内存分配给进程就可以了。但如果内存还是不足,OOM 就要登场。

OOM 发生时,你可以在 dmesg 中看到 Out of memory 的信息,从而知道是哪些进程被 OOM 杀死了。比如,你可以执行下面的命令,查询 OOM 日志

dmesg | grep -i "Out of memory"

OOM什么时候会发生?

OOM 触发的时机基于虚拟内存。换句话说,进程在 申请内存时,如果申请的虚拟内存加上服务器实际已用的内存之和,比总的物理内存还大,就会触发 OOM

因此不能单纯的看cache和 buffer还有很多,实际可回收的有多少呢?回收的能赶得上请求分配吗?

四、NUMA 与 Swap关系

很多情况下,你明明发现了 Swap 升高,可是在分析系统的内存使用时,却很可能发现,系统剩余内存还多着呢。为什么剩余内存很多的情况下,也会发生 Swap 呢?这正是处理器的 NUMA (Non-UniformMemory Access)架构导致的。

在 NUMA 架构下,多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间。而同一个 Node 内部的内存空间,实际上又可以进一步分为不同的内存域(Zone),比如 直接内存访问区 (DMA)、 普通内存区 (NORMAL)、 伪内存区 (MOVABLE)等,如下图所示

十九、为什么系统的Swap变高了?

先不用特别关注这些内存域的具体含义,我们只要会查看 阈值的配置 ,以及 缓存、匿名页的实际使用情况 就够了既然 NUMA 架构下的每个 Node 都有自己的本地内存空间,那么,在分析内存的使用时,我们也应该针对每个 Node 单独分析。

你可以通过 numactl 命令,来查看处理器在 Node 的分布情况,以及每个 Node 的内存使用情况

 tune]$ numactl --hardwareavailable: 2 nodes (0-1)node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 24 25 26 27 28 29 30 31 32 33 34 35node 0 size: 163710 MBnode 0 free: 654 MBnode 1 cpus: 12 13 14 15 16 17 18 19 20 21 22 23 36 37 38 39 40 41 42 43 44 45 46 47node 1 size: 163840 MBnode 1 free: 11017 MBnode distances:node   0   1   0:  10  21   1:  21  10 

这个界面显示,我的系统中有两个 Node

编号为 0 1 2 3 4 5 6 7 8 9 10 11 24 25 26 27 28 29 30 31 32 33 34 35的24个CPU, 都位于 Node 0 上。

编号为12 13 14 15 16 17 18 19 20 21 22 23 36 37 38 39 40 41 42 43 44 45 46 47 的24个CPU, 都位于 Node1 上。

另外,Node 0 的内存大小为 163710 MB,剩余内存为 654MB

Node 1 的内存大小为 163840 MB,剩余内存为 11017MB

了解了 NUNA 的架构和 NUMA 内存的查看方法后,你可能就要问了这跟 Swap 有什么关系呢?

前面提到的三个内存阈值(页最小阈值、页低阈值和页高阈值),都可以通过内存域在 proc 文件系统中的接口 /proc/zoneinfo 来查看

tune]$ cat /proc/zoneinfo|moreNode 0, zone      DMA  pages free     3936        min      0        low      0        high     0        scanned  0        spanned  4095        present  3841    nr_free_pages 3936    nr_inactive_anon 0    nr_active_anon 0    nr_inactive_file 0    nr_active_file 0    nr_unevictable 0    nr_mlock     0    nr_anon_pages 0    nr_mapped    0    nr_file_pages 0    nr_dirty     0    nr_writeback 0    nr_slab_reclaimable 0    nr_slab_unreclaimable 0    nr_page_table_pages 0    nr_kernel_stack 0    nr_unstable  0    nr_bounce    0    nr_vmscan_write 0    nr_writeback_temp 0    nr_isolated_anon 0    nr_isolated_file 0    nr_shmem     0    numa_hit     0    numa_miss    0    numa_foreign 0    numa_interleave 0    numa_local   0    numa_other   0    nr_anon_transparent_hugepages 0        protection: (0, 1846, 161426, 161426)  pagesets    cpu: 0              count: 0              high:  0              batch: 1  vm stats threshold: 12    cpu: 1              count: 0              high:  0              batch: 1  vm stats threshold: 12    cpu: 2              count: 0              high:  0              batch: 1  vm stats threshold: 12    cpu: 3              count: 0              high:  0              batch: 1  vm stats threshold: 12......

pages 处的 min、low、high,就是上面提到的三个内存阈值,而 free 是剩余内存页数,它跟后面的 nr_free_pages 相同。 nr_zone_active_anon 和 nr_zone_inactive_anon,分别是活跃和非活跃的匿名页数。nr_zone_active_file 和 nr_zone_inactive_file,分别是活跃和非活跃的文件页数

剩余内存远大于页高阈值,所以此时的 kswapd0 不会回收内存。

某个 Node 内存不足时,系统可以从其他 Node 寻找空闲内存,也可以从本地内存中回收内存。具体选哪种模式,你可以通过 /proc/sys/vm/zone_reclaim_mode 来调整

  • 默认的 0 ,表示既可以从其他 Node 寻找空闲内存,也可以从本地回收内存。
  • 1、2、4 都表示只回收本地内存
  • 2 表示可以回写脏数据回收内存4 表示可以用Swap 方式回收内存

五、swappiness

  1. 对文件页的回收,当然就是直接回收缓存,或者把脏页写回磁盘后再回收。
  2. 对匿名页的回收,其实就是通过 Swap 机制,把它们写入磁盘后再释放内存

既然有两种不同的内存回收机制,那么在实际回收内存时,到底该先回收哪一种呢?

Linux 提供了一个 /proc/sys/vm/swappiness选项,用来调整使用 Swap 的积极程度。

swappiness 的范围是 0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页swappiness 的范围是 0-100,不过要注意,这并不是内存的百分比,而是调整Swap 积极程度的权重,即使你把它设置成 0,当 剩余内存 + 文件页小于页高阈值时 ,还是会发生 Swap。