本文由 简悦 SimpRead 转码, 原文地址 zhuanlan.zhihu.com

    • 背景
    1. Swap 把不常访问的内存先写到磁盘中,
    2. 然后释放这些内存,给其他更需要的进
    3. 程使用。再次访问这些内存时,重新从
    4. 磁盘读入内存
    5. 有新的大块内存分配请求,但是剩余内存不足。
    6. 这个时候系统就需要回收一部分内存(比如前
    7. 面提到的缓存),进而尽可能地满足新内存请求。
    8. 这个过程通常被称为直接内存回收。
    9. 除了直接内存回收,还有一个专门的内核线程
    10. 用来定期回收内存,也就是 kswapd0
    • kswapd0
    1. 为了衡量内存的使用情况,kswapd0 定义了三个内存阈值
    2. watermark,也称为水位),分别是页最小阈值(pages_min
    3. 、页低阈值(pages_low)和页高阈值(pages_high)。
    4. 剩余内存,则使用 pages_free 表示。

    内存性能篇-swap的概念 - 图1

    1. kswapd0 定期扫描内存的使用情况,并根据剩余内存落在这三个阈值
    2. 的空间位置,进行内存的回收操作。
    3. 剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可
    4. 以分配内存。
    5. 剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较
    6. 大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩
    7. 余内存大于高阈值为止。
    8. 剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满
    9. 足新内存请求。
    10. 剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力
    11. 这个页低阈值,其实可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间
    12. 接设置。min_free_kbytes 设置了页最小阈值,而其他两个阈值,都是根据页
    13. 最小阈值计算生成的,计算方法如下:
    14. pages_low = pages_min*5/4
    15. pages_high = pages_min*3/2
    • 为什么剩余内存很多但是 swap 却在升高
    1. 处理器的 NUMA Non-Uniform Memory Access)架构导致的
    2. NUMA 架构下,多个处理器被划分到不同 Node 上,且每个
    3. Node 都拥有自己的本地内存空间。而同一个 Node 内部的
    4. 内存空间,实际上又可以进一步分为不同的内存域(Zone),
    5. 比如直接内存访问区(DMA)、普通内存区(NORMAL)、伪内
    6. 存区(MOVABLE)等,如下图所示

    内存性能篇-swap的概念 - 图2

    1. NUMA 架构下的每个 Node 都有自己的本地内存空间,那么,在分析
    2. 内存的使用时,我们也应该针对每个 Node 单独分析。你可以通过
    3. numactl 命令,来查看处理器在 Node 的分布情况,以及每个 Node
    4. 内存使用情况。比如,下面就是一个 numactl 输出的示例
    5. # 需要安装apt install numactl
    6. root@ubuntu:~# numactl --hardware
    7. available: 1 nodes (0)
    8. node 0 cpus: 0 1 2 3
    9. node 0 size: 7953 MB
    10. node 0 free: 5699 MB
    11. node distances:
    12. node 0
    13. 0: 10
    14. 我的系统中只有一个 Node,也就是 Node 0 ,而且编号为 0 123 的四个 CPU
    15. 都位于 Node 0 上。另外,Node 0 的内存大小为 7953 MB,剩余内存为 4416 MB
    • 内存阈值查看
    1. root@ubuntu:~# cat /proc/zoneinfo
    2. Node 0, zone DMA
    3. per-node stats
    4. nr_inactive_anon 2668
    5. nr_active_anon 232344
    6. nr_inactive_file 99975
    7. nr_active_file 97279
    8. nr_unevictable 4
    9. nr_slab_reclaimable 14518
    10. nr_slab_unreclaimable 17376
    11. nr_isolated_anon 0
    12. nr_isolated_file 0
    13. workingset_refault 0
    14. workingset_activate 0
    15. workingset_nodereclaim 0
    16. nr_anon_pages 232008
    17. nr_mapped 64949
    18. nr_file_pages 200270
    19. nr_dirty 52
    20. nr_writeback 0
    21. nr_writeback_temp 0
    22. nr_shmem 3017
    23. nr_shmem_hugepages 0
    24. nr_shmem_pmdmapped 0
    25. nr_anon_transparent_hugepages 0
    26. nr_unstable 0
    27. nr_vmscan_write 0
    28. nr_vmscan_immediate_reclaim 0
    29. nr_dirtied 35872
    30. nr_written 29016
    31. pages free 3968
    32. min 33
    33. low 41
    34. high 49
    35. spanned 4095
    36. present 3997
    37. managed 3976
    38. protection: (0, 2911, 7878, 7878, 7878)
    39. nr_free_pages 3968
    40. nr_zone_inactive_anon 0
    41. nr_zone_active_anon 0
    42. nr_zone_inactive_file 0
    43. nr_zone_active_file 0
    44. nr_zone_unevictable 0
    45. nr_zone_write_pending 0
    46. nr_mlock 0
    47. 上面参数单位是多杀?
    48. pages 处的 minlowhigh,就是上面提到的三个内存阈值,
    49. free 是剩余内存页数,它跟后面的 nr_free_pages 相同。
    50. nr_zone_active_anon nr_zone_inactive_anon,分别是活
    51. 跃和非活跃的匿名页数。nr_zone_active_file nr_zone_inactive_file
    52. 分别是活跃和非活跃的文件页数。从这个输出结果可以发现,剩
    53. 余内存远大于页高阈值,所以此时的 kswapd0 不会回收内存

    Node 扩充内存的方法

    1. 某个 Node 内存不足时,系统可以从其他 Node 寻找空闲内存,
    2. 也可以从本地内存中回收内存。具体选哪种模式,你可以通过
    3. /proc/sys/vm/zone_reclaim_mode 来调整。
    4. 它支持以下几个选项:默认的 0 ,也就是刚刚提到的模式,
    5. 表示既可以从其他 Node 寻找空闲内存,也可以从本地回收内存。
    6. 124 都表示只回收本地内存,2 表示可以回写脏数据回收
    7. 内存,4 表示可以用 Swap 方式回收内存。
    8. 查看命令:
    9. root@ubuntu:~# cat /proc/sys/vm/zone_reclaim_mode
    10. 0

    swappiness 权重配置

    1. 内存回收的机制了。这些回收的内存既包括了文件页,
    2. 又包括了匿名页。
    3. 对文件页的回收,当然就是直接回
    4. 收缓存,或者把脏页写回磁盘后再回收。
    5. 而对匿名页的回收,其实就是通过 Swap 机制,
    6. 把它们写入磁盘后再释放内存。
    7. 既然有两种不同的内存回收机制,
    8. 那么在实际回收内存时,到底该先回收哪一种呢?
    9. 其实,Linux 提供了一个 /proc/sys/vm/swappiness
    10. 项,用来调整使用 Swap 的积极程度。swappiness 的范
    11. 围是 0-100,数值越大,越积极使用 Swap,也就是更倾
    12. 向于回收匿名页;数值越小,越消极使用 Swap,也就是
    13. 更倾向于回收文件页。虽然 swappiness 的范围是 0-100
    14. 不过要注意,这并不是内存的百分比,而是调整 Swap 积极
    15. 程度的权重,即使你把它设置成 0,当剩余内存 + 文件页小
    16. 于页高阈值时,还是会发生 Swap
    • 总结
    1. 在内存资源紧张时,Linux 通过直接内存回收和定期扫描
    2. 的方式,来释放文件页和匿名页,以便把内存分配给更需
    3. 要的进程使用。
    4. 文件页的回收比较容易理解,直接清空,或者把脏数据写
    5. 回磁盘后再释放。
    6. 而对匿名页的回收,需要通过 Swap 换出到磁盘中,下次访
    7. 问时,再从磁盘换入到内存中。