当发生内存泄漏,或运行大内存的应用,导致系统的内存资源紧张时。
1、导致OOM(Out Of Memory)
2、内存回收,也就是系统释放掉可以回收的内存,比如前面的缓存和缓冲区,就属于可回收内存。在内存管理中,通常被叫做 文件页(File-backed Page)。
大部分文件页,可以直接回收。而被应用程序修改过,并且暂时没写入磁盘的数据(脏页),得先写入磁盘,然后才能进行内存释放。写入磁盘方式

  • 在应用程序中,通过系统调用 fsync,把脏页同步到磁盘中
  • 系统,由内核线程 pdflush 负责这些脏页的刷新

应用程序动态分配的堆内存,也就是内存管理中的 匿名页(Anonymous Page),也不能直接释放。

1、原理

swap 就是把一块磁盘空间或者一个本地文件,当成内存来使用。包括

  • 换出:把进程暂时不用的内存数据存储到磁盘中,并释放这些数据占用的内存
  • 换入:在进程再次访问这些内存的时候,把他们从磁盘读到内存中来

    2、衡量内存不足

    1、直接内存回收

    有新的大块内存分配需求,但剩余内存不足。系统需要回收一部分内存(如缓存),进而尽可能地满足新内存的请求。

    2、定期扫描回收

    有一个专门的 内核线程 来定期回收内存,即 kswapd0
    它定义了三个内存阈值(watermark,水位)
    image.png
    这个 页低阈值,可以通过内核选项 /proc/sys/vm/min_free_kbytes来设置。其他两个阈值,是根据这个计算的
    1. pages_low = pages_min*5/4
    2. pages_high = pages_min*3/2

    3、NUMA与SWAP

    在内存很多的情况下,也会发生 Swap,这是因为 在 NUMA 架构下,多个处理器被划分到不同 node 上,每个 node 有自己的本地存储空间。他们的内部存储空间,又分为不同的内存域(Zone)。
    image.png
    查看node情况
    image.png
    系统中只有一个 Node,也就是 Node 0 ,而且编号为 0 和 1 的两个 CPU, 都位于 Node 0 上。另外,Node 0 的内存大小为 3919 MB,剩余内存为 3017 MB。

三个内存阈值(页最小阈值、页低阈值和页高阈值),都可以通过内存域在 proc 文件系统中的接口 /proc/zoneinfo来查看。
image.png
可以看到剩余内存远高于 页最高阈值,kswapd0 也不会回收内存。
当某个 node 内存不足时,系统会从其他 node 寻找空闲内存,也可以从本地内存中回收内存。具体模式可以通过 /proc/sys/vm/zone_reclaim_mode 来调整。

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

    4、swappiness

  • 对文件页回收,直接回收缓存,或把脏页写会磁盘后再回收

  • 对匿名页回收,通过Swap机制,写入磁盘后释放内存

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

5、工具

1、free

查看swap的情况
image.png

2、sar

查看系统内存和swap的实时使用情况

  1. # 间隔1秒输出一组数据
  2. # -r表示显示内存使用情况,-S表示显示Swap使用情况
  3. sar -r -S 1

image.png

3、/proc/zoneinfo

  1. # -d 表示高亮变化的字段
  2. # -A 表示仅显示Normal行以及之后的15行输出
  3. watch -d grep -A 15 'Normal' /proc/zoneinfo

image.png

4、smem

可以将进程按照 swap 使用率排序显示
image.png

5、分析

当 /proc/zoneinfo 看到剩余内存(pages_free)在一个小范围内不停地波动。当它小于页低阈值(pages_low) 时,又会突然增大到一个大于页高阈值(pages_high)的值。
再结合刚刚用 sar 看到的 刚开始,剩余内存(kbmemfree)不断减少,而缓冲区(kbbuffers)则不断增大,由此可知,剩余内存不断分配给了缓冲区。一段时间后,剩余内存已经很小,而缓冲区占用了大部分内存。这时候,Swap 的使用开始逐渐增大,缓冲区和剩余内存则只在小范围内波动。
可以推导出,剩余内存和缓冲区的波动变化,正是由于内存回收和缓存再次分配的循环往复