在Linux系统中,每个进程都独有一个虚拟地址空间(Virtual Address Space),由内核维护内存映射。为完成内存映射(虚拟内存地址映射到物理内存地址),内核为每一个进程维护一张页表。而页表存储在CPU的内存管理单元MMU中(即通过硬件完成了内存地址的查找)。
当进程访问的虚拟地址在页表中找不到时,就会产生缺页异常。此时会陷入内核空间完成物理内存分配、更新进程页表,然后恢复进程运行。
MMU以页为单位来管理内存,每个页通常为4KB大小,所以每一次内存映射需要关联4KB的整数倍的内存空间。
为了解决页表项过大问题,Linux提供多级页表(实际上是四级页表)和大页(HugePage)机制。
Linux的虚拟地址空间,大大增加了进程的寻址空间,32位系统的虚拟地址空间分布如图:
ulimit -s
查看对于64为Linux,内核空间占据顶部128T的虚拟地址空间,用户空间占据底部128T的虚拟地址空间。中间部分是未定义的。
另一张Linux虚拟地址空间分布图:
通过Linux虚拟地址空间分布,我们可以看出,Linux内存回收主要针对堆和文件映射区域。
Linux提供2种内存回收时机:
当发生内存分配,而此时的剩余空闲内存不足时,会执行立即内存回收。
内核线程kswapd
会定期扫描内存使用量,当剩余内存小于pages_free_low
的值时,会进行内存回收,并确保可用内存高于pages_free_high
。可通过修改/proc/sys/vm/min_free_kbytes
文件的值来修改pages_free_min
的值,另外两个值会自动计算得出。
NUMA架构中,每一个NUMA节点都会有一个kswapd线程。可通过numactl --hardware
命令查看NUMA节点信息。
# cat /proc/sys/vm/min_free_kbytes
90112
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 20 21 22 23 24 25 26 27 28 29
node 0 size: 32642 MB
node 0 free: 188 MB
node 1 cpus: 10 11 12 13 14 15 16 17 18 19 30 31 32 33 34 35 36 37 38 39
node 1 size: 32768 MB
node 1 free: 68 MB
node distances:
node 0 1
0: 10 21
1: 21 10
Linux通过以下方式进行内存回收:
oom_score
大的程序:内存占用越大,oom_score
越大,越容易被OOM;cpu占用越多,oom_score
越小,越不容易被OOM;可通过/proc/$PID/oom_adj
来影响oom_score
的值,取值范围[-17, 15]
。/proc/sys/vm/drop_caches
的值进行手动回收,最好再执行下sync
命令回写脏页
通过修改/proc/sys/vm/swappiness
文件的值,使系统更倾向于回收匿名页或文件页,取值范围[0, 100]。
数值越大,越倾向于回收匿名页,越积极使用swap;
数值越小,越倾向于回收文件页,越消极使用swap;
但即使设置为0,仍然会使用swap。
在NUMA
架构中,多处理器被划分到不同Node
上,而同一个Node
又进一步被换分为不同的内存域(Zone
)。
在Linux中,默认开启NUMA,在我的系统(rhel6.5)上,64G的内存被划分为2个Node
:
# yum install -y numactl
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14
node 0 size: 32757 MB
node 0 free: 237 MB
node 1 cpus: 1 3 5 7 9 11 13 15
node 1 size: 32767 MB
node 1 free: 137 MB
node distances:
node 0 1
0: 10 20
1: 20 10
当某node内存不足时,系统可以选择从其他node寻找空间内存,也可以选择从本node回收内存。具体偏好可以通过/proc/sys/vm/zone_reclaim_mode
文件来控制。
可以通过修改内核启动参数来禁用MUNA。
vi /boot/grub/grub.conf
...
kernel /boot/vmlinuz-2.6.18-128.1.16.0.1.el5 root=LABEL=DBSYS ro bootarea=dbsys rhgb quiet console=ttyS0,115200n8 console=tty1 crashkernel=128M@16M numa=off
...
可通过cat /proc/$PID/status | grep VmSwap
查看进程使用的swap情况。
也可通过smem
命令查看进程使用的swap量。
查看swap使用最大的前10个进程:
# smem --sort swap -r | head -10
PID User Command Swap USS PSS RSS
12076 999 mysqld 446756 60560 60894 61232
22757 mysql /usr/sbin/mysqld 61236 4360 4471 5520
11864 root /usr/bin/dockerd -H fd:// - 24848 16212 16212 16216
588 root /usr/bin/containerd 13064 9688 9688 9692
590 root /usr/bin/python3 /usr/share 7996 8 8 12
515 root /usr/bin/python3 /usr/bin/n 7840 4 4 8
12225 root php-fpm: master process (/u 5988 52 71 116
4305 root -bash 3644 1852 2030 3196
12368 www-data php-fpm: pool ww 3076 4668 6913 9184
查看每个用户的使用率
# smem -u
User Count Swap USS PSS RSS
nagios 1 0 704 728 1500
chrony 1 0 700 885 2040
dbus 1 0 892 1123 2508
nobody 16 0 8832 9712 34300
polkitd 1 0 11236 12009 14352
root 28 0 194864 218192 269140
查看某进程(正则表达式匹配进程名):
# smem -P nginx
PID User Command Swap USS PSS RSS
1423 root nginx: master process /usr/ 0 152 186 1160
1425 nobody nginx: worker process 0 552 607 2144
1426 nobody nginx: worker process 0 552 607 2144
1427 nobody nginx: worker process 0 552 607 2144
1428 nobody nginx: worker process 0 552 607 2144
1429 nobody nginx: worker process 0 552 607 2144
1430 nobody nginx: worker process 0 552 607 2144
1431 nobody nginx: worker process 0 552 607 2144
1434 nobody nginx: worker process 0 552 607 2144
1435 nobody nginx: worker process 0 552 607 2144
1436 nobody nginx: worker process 0 552 607 2144
1437 nobody nginx: worker process 0 552 607 2144
1438 nobody nginx: worker process 0 552 607 2144
1439 nobody nginx: worker process 0 552 607 2144
1440 nobody nginx: worker process 0 552 607 2144
1441 nobody nginx: worker process 0 552 607 2144
1442 nobody nginx: worker process 0 552 607 2140
9278 root python /usr/bin/smem -P ngi 0 4628 5319 6820
nocache软件包提供cachestats
和cachedel
命令行工具,可查看、清理某文件在内存中的缓存。
bcc软件包中也提供一个cachestats
命令行工具,可提供整个操作系统缓存的读写命中情况,另外还包含cachetop来提供每个进程的缓存命中情况。安装bcc软件包可能需要升级内核至4.1。
root@blog:~# cachestats /root/holiday.py
pages in cache: 0/1 (0.0%) [filesize=2.4K, pagesize=4K]
root@blog:~# cat /root/holiday.py &> /dev/null
root@blog:~# cachestats /root/holiday.py
pages in cache: 1/1 (100.0%) [filesize=2.4K, pagesize=4K]
root@blog:~# cachedel /root/holiday.py
root@blog:~# cachestats /root/holiday.py
pages in cache: 0/1 (0.0%) [filesize=2.4K, pagesize=4K]
/proc/sys/vm
目录包含内存管理调优、buffer、cache管理的文件,这些参数用来调整Virtual Memory子系统的行为以及数据的写出(从RAM到ROM),具体如下。
文件 | 默认值 | 含义 |
---|---|---|
/proc/sys/vm/admin_reserve_kbytes | 3%的free pages与8MB中较小的值 | 系统中为拥有cap_sys_admin的权限(可以大致理解到root权限)的user预留的free memory数量。增大该值以保证root可登录并恢复系统。该值的修改需要考虑root登录后使用的工具(ssh、bash、ps、top、netstat等),一般推荐VSS+RSS。 |
/proc/sys/vm/block_dump | 0,禁用 | 是否打开Block Debug模式,用于记录所有的读写及Dirty Block写回动作。 |
/proc/sys/vm/dirty_background_bytes | 0 | 与dirty_background_ratio互斥,不可同时使用,设置了dirty_background_ratio之后,此项会变成0; 该文件定义脏数据的量,此时触发后台内核线程把脏数据写回磁盘 |
/proc/sys/vm/dirty_background_ratio | 10 | 与dirty_background_bytes互斥,不可同时使用; 脏数据所占的页面,占包括free页面和可回收页面的在内的总可用页面数的百分比,此时触发后台内核线程将脏数据写回磁盘。这里说的总可用内存不等于系统的总内存。 |
/proc/sys/vm/dirty_expire_centisecs | 3000(单位是1/100秒,即3s) | 该文件表示如果脏数据在内存中驻留时间超过该值,后台内核线程会在下一次将把这些数据写回磁盘。 |
/proc/sys/vm/dirty_ratio | 40 | 该文件表示如果进程产生的脏数据所占页面,占包括free页面和可回收页面的在内的总可用页面数的百分比,磁盘写操作的进程会自动把脏数据写回磁盘 |
/proc/sys/vm/dirty_writeback_centisecs | 500(单位是1/100秒,即0.5s) | 该文件表示后台内核线程周期性间隔多久把脏数据写回磁盘(即多少间隔唤醒一次)。 |
/proc/sys/vm/drop_caches | 0 | 写入文件对应的值可使内核回收释放pagecache(即文件页,包括cache、buffer、通过内存映射的文件映射页)、目录缓存和inodes,从而得到更多空闲内存。 该操作是非破坏性的,脏数据不会被释放,应该在运行之前执行sync命令将所有缓存对象释放。 1:释放pagecache; 2:释放目录缓存和inodes; 3:释放pagecache、目录缓存和inodes; |
/proc/sys/vm/hugetlb_shm_group | 0 | 该文件表示允许使用hugetlb页创建System VIPC共享内存段的系统组ID。 |
/proc/sys/vm/legacy_va_layout | 0 | 该文件表示是否使用最新的32位共享内存mmap()系统调用,Linux支持的共享内存分配方式包括mmap(),Posix,System VIPC。0,使用最新32位mmap()系统调用。1,使用2.4内核提供的系统调用。 |
/proc/sys/vm/min_free_kbytes | 724(512M物理内存) | 该文件表示强制Linux VM最低保留多少空闲内存(Kbytes)。 |
/proc/sys/vm/min_slab_ratio | 5(%) | 仅适用NUMA架构中; zone中可回收页面占总页面的百分比,超过后则进行回收; slab回收是基于每个zone/node的方式来触发的,这个过程可能不太快; |
/proc/sys/vm/nr_hugepages | 0 | 该文件表示系统保留的hugetlb页数。 |
/proc/sys/vm/nr_pdflush_threads | 2(只读) | 该文件表示当前正在运行的pdflush进程数量,在I/O负载高的情况下,内核会自动增加更多的pdflush进程。 |
/proc/sys/vm/overcommit_memory | 0 | 该文件指定了内核针对内存分配的策略,其值可以是0、1、2。0,表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。2,表示内核允许分配超过所有物理内存和交换空间总和的内存(参照overcommit_ratio) |
/proc/sys/vm/overcommit_ratio | 50(%) | 该文件表示,如果overcommit_memory=2,可以过载内存的百分比,通过以下公式来计算系统整体可用内存。系统可分配内存=交换空间+物理内存*overcommit_ratio/100 |
/proc/sys/vm/page-cluster | 3(2的3次方,8页) | 该文件表示在写一次到swap区的时候写入的页面数量,0表示1页,1表示2页,2表示4页。 |
/proc/sys/vm/swapiness | 60 | 该文件表示系统进行交换行为的程度,数值(0-100)越高,越可能发生磁盘交换。 |
/proc/sys/vm/vfs_cache_pressure | 100 | 该文件表示内核回收用于directory和inode cache内存的倾向;缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比;降低该值低于100,将导致内核倾向于保留directory和inode cache;增加该值超过100,将导致内核倾向于回收directory和inode cache。 |
/proc/sys/vm
中各文件含义大部分摘自:
https://www.cnblogs.com/xianbei/archive/2012/11/23/2783818.html
/proc/sys/vm
中各文件含义部分内容参考:
https://blog.csdn.net/cassie_huang/article/details/80633328
smem命令:
https://linux.cn/article-4492-1.html
其他参考:
https://blog.csdn.net/weixin_33800593/article/details/90681825
https://cloud.tencent.com/developer/article/1004428
https://cloud.tencent.com/developer/article/1004429