问题背景
有小伙伴反馈客户生产环境(裸机部署)频繁告警可用内存不足,但是计算出来每个进程的内存使用总和不多,那多出来的内存哪里去了呢?
通过 free 命令我们能计算出来系统的使用内存 (used=11G),free 内存 (free=4.8G)
当前 linux 系统的版本是 RHEL 6.8 内核 kernel 版本 2.6.32
top 命令里面展示的 top 进程使用的 RES 内存总和不到 6G,
剩余的 11-6=5G 哪里去了呢?
被系统内核占用了?
那怎么才能看到系统内存的详细分配情况?
带着这些疑问我们来梳理 linux 中常见的查看系统内存资源一些命令和详细的指标解释,包括一些参数配置的最佳实践
命令集
free 命令
命令
选项
-b # 以Byte为单位显示内存使用情况;-k # 以KB为单位显示内存使用情况;-m # 以MB为单位显示内存使用情况;-g # 以GB为单位显示内存使用情况。 -o # 不显示缓冲区调节列;-s<间隔秒数> # 持续观察内存使用状况;-t # 显示内存总和列;-V # 显示版本信息。
复制代码
数据
free -m total used free shared buffers cachedMem: 2016 1973 42 0 163 1497-/+ buffers/cache: 312 1703Swap: 4094 0 4094
复制代码
注意:RHEL 6 和 RHEL 7 及以上版本可能还不一样,7 以上版本会多一项数据指标 avaliable,会帮你把真实可用的内存值算出来。
含义解释
Mem 行显示的数值定义
total:系统内存总数
used:已经使用的内存数
free: 空闲的内存数
shared:当前已经废弃不用
buffers:缓存内存数
cached:缓存内存数
Buffers 和 cached 的区别
Buffers
作为 buffer cache 的内存,是块设备的读写缓冲区,是即将写入磁盘的,是内存和磁盘之间的缓存
buffer 是由各种进程分配的,被用在如输入队列等方面。一个简单的例子如某个进程要求有多个字段读入,在所有字段被读入完整之前,进程把先前读入的字段放在 buffer 中保存
cached
作为 page cache 的内存, 文件系统的 cache,是 cpu 到内存之间的缓存,是从磁盘中读出来的数据的缓存
cache 经常被用在磁盘的 I/O 请求上,如果有多个进程都要访问某个文件,于是该文件便被做成 cache 以方便下次被访问,这样可提高系统性能
如何释放缓存
#释放page cacheecho 1 > /proc/sys/vm/drop_caches----------------------------------------#释放 Linux 系统中的 dentries(目录项)和 inodes(索引节点)所占用的资源echo 2 > /proc/sys/vm/drop_caches----------------------------------------
#释放 page cache 及 dentries(目录项)和 inodes(索引节点)所占用的资源echo 3 > /proc/sys/vm/drop_caches
----------------------------------------#释放前最好sync一下,防止丢失数据,但是一般情况下没有必要手动释放内存
复制代码
(-/+ buffers/cache)是从用户角度描述内存使用详情
used = Mem 行的 used-buffers-cached
free = Mem 行的 free+buffers+cached
SWAP
在 Linux 系统中,Swap 是一种虚拟内存技术,用于扩展系统的可用内存空间。当物理内存(RAM)不足时,Swap 允许将一部分数据从内存交换到硬盘上的 Swap 分区或 Swap 文件中
SWAP 的优势
扩展内存:Swap 提供了一种方式来增加系统可用的虚拟内存空间,以处理内存需求超过物理内存容量的情况
保证系统的稳定:当物理内存不足时,Swap 可以避免系统崩溃或进程被终止,而是将一部分数据交换到磁盘上
SWAP 的值设置的最佳实践
针对小型的系统物理内存的倍数:一般来说,建议将 Swap 的大小设置为物理内存的 1-2 倍
对于大型的系统可以设置为内存的一半:如 16G 的物理内存,可以把 SWAP 设置为 8G
考虑应用系统的类型,对于内存密集型的系统,建议把 SWAP 值尽量提高
保留系统的冗余能力
linux 上查看 Swap 设置值大小和修改方法
查看
#查看方式1swapon --show---------------------------------------------NAME TYPE SIZE USED PRIO/dev/dm-1 partition 15.7G 12G -2---------------------------------------------#查看方式2cat /etc/fstab--------------------------------------------/dev/mapper/centos-root / xfs defaults 0 0UUID=5daa0a7f-cc95-4a7d-9aeb-94816daf4025 /boot xfs defaults 0 0/dev/mapper/centos-home /home xfs defaults 0 0/dev/mapper/centos-swap swap swap defaults 0 0---------------------------------------------# swap 和dm-1建立的是软连接---------------------------------------------lrwxrwxrwx. 1 root root 7 5月 22 20:10 centos-swap -> ../dm-1---------------------------------------------
复制代码
#创建 Swap 分区(可选)---------------------------------------------sudo mkswap /dev/mapper/test-swap---------------------------------------------#方法一---------------------------------------------sudo swapon /dev/mapper/test-swap---------------------------------------------
#方法二(永久设置 Swap 分区)#编辑上文中的/etc/fstab 文件,并添加以下行到文件末尾---------------------------------------------vim /etc/fstab---------------------------------------------#添加代码---------------------------------------------/dev/mapper/test-swap none swap defaults 0 0---------------------------------------------
复制代码
#关闭swapswapoff /dev/mapper/test-swap
复制代码
修改触发 swap 的阈值 (定义:内存在使用到 100-swappiness 的时候,就开始出现有交换分区的使用)
0:在任何情况下都不发生物理内存数据和 swap 文件的交换
100:表示积极进行物理内存数据和 swap 数据的交换
#查看阈值cat /proc/sys/vm/swappiness---------------------------------------------30---------------------------------------------
#临时修改sysctl vm.swappiness=60
#永久修改vim /etc/sysctl.conf
#添加vm.swappiness=60
复制代码
物理内存和 Swap 使用的优先级和策略
物理内存优先
当物理内存不足时,系统会将一部分不活动的数据(如未使用的进程、未被频繁访问的页面等)交换到 Swap 分区或交换文件中
Linux 内核中使用的内存管理算法会根据应用程序的需求和系统的负载情况来决定何时将数据交换到 Swap
Swappiness 值
Swap 中的数据何时回返还到物理内存中
内存需求减少
通过一些计算算法,发现部分频繁访问的数据在 swap 区,而物理内存中存在不经常被访问的数据,这个时候系统会做热点数据的交换,以保证获得更高的数据读取性能
Top 命令
top 命令面板
指标解析
load average: 如果这个数除以逻辑 CPU 的数量,结果高于 5 的时候就表明系统在超负荷运转了。
|
默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 几个列!
如果想看上述列表中的其他数据,先按键 f ,再选择你想展示的指标 ,按 d 选中 回车。q 退出
top#按 f------------------------------------------------------------------* PID = Process Id RSfd = RES File-based (KiB)* USER = Effective User Name RSlk = RES Locked (KiB) * PR = Priority RSsh = RES Shared (KiB) * NI = Nice Value CGNAME = Control Group name * VIRT = Virtual Image (KiB) NU = Last Used NUMA node * RES = Resident Size (KiB) * SHR = Shared Memory (KiB) * S = Process Status * %CPU = CPU Usage * %MEM = Memory Usage (RES) * TIME+ = CPU Time, hundredths* COMMAND = Command Name/Line PPID = Parent Process pid UID = Effective User Id RUID = Real User Id RUSER = Real User Name SUID = Saved User Id SUSER = Saved User Name GID = Group Id GROUP = Group Name PGRP = Process Group Id TTY = Controlling Tty TPGID = Tty Process Grp Id SID = Session Id nTH = Number of Threads P = Last Used Cpu (SMP) TIME = CPU Time SWAP = Swapped Size (KiB) CODE = Code Size (KiB) DATA = Data+Stack (KiB) nMaj = Major Page Faults nMin = Minor Page Faults nDRT = Dirty Pages Count WCHAN = Sleeping in Function Flags = Task Flags <sched.h> CGROUPS = Control Groups SUPGIDS = Supp Groups IDs SUPGRPS = Supp Groups Names TGID = Thread Group Id OOMa = OOMEM Adjustment OOMs = OOMEM Score current ENVIRON = Environment vars vMj = Major Faults delta vMn = Minor Faults delta USED = Res+Swap Size (KiB) nsIPC = IPC namespace Inode nsMNT = MNT namespace Inode nsNET = NET namespace Inode nsPID = PID namespace Inode nsUSER = USER namespace Inode nsUTS = UTS namespace Inode LXC = LXC container name RSan = RES Anonymous (KiB) ------------------------------------------------------------------# 选中想要展示的指标 按d 选中 按q 退出------------------------------------------------------------------
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND PPID TTY CODE DATA 6218 systemd+ 20 0 1740884 404556 0 S 0.3 10.5 420:03.84 mysqld 6201 ? 55828 806684 6768 root 20 0 2736204 410092 3368 S 0.3 10.6 103:43.46 java 6750 pts/0 4 615804 1 root 20 0 178784 10308 7468 S 0.0 0.3 172:31.49 systemd 0 ? 1260 20720 2 root 20 0 0 0 0 S 0.0 0.0 0:03.22 kthreadd 0 ? 0 0 3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp 2 ? 0 0 4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp 2 ? 0 0 6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-kblockd 2 ? 0 0 8 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq 2 ? 0 0 9 root 20 0 0 0 0 S 0.0 0.0 2:54.83 ksoftirqd/0 2 ? 0 0 10 root 20 0 0 0 0 I 0.0 0.0 26:28.63 rcu_sched 2 ? 0 0 11 root rt 0 0 0 0 S 0.0 0.0 0:05.90 migration/0 2 ? 0 0 12 root rt 0 0 0 0 S 0.0 0.0 0:00.60 watchdog/0 2 ? 0 0 13 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/0 2 ? 0 0 14 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/1 2 ? 0 0
复制代码
常用命令
top + c 显示启动命令
top + m 按照内存使用从高到低进程排序
top + P 按照 cpu 使用从高到低进程排序
top + 1 显示每个 cpu 的使用情况
重点指标
RES(Resident Set Size):RES 表示进程当前实际占用的物理内存大小。它包括进程的代码、数据和共享库等在物理内存中的部分。RES 反映了进程实际使用的物理内存量,也可以理解为进程当前使用的实际内存。RES 的值通常大于 DATA+CODE 的值
VIRT(Virtual Memory Size):VIRT 表示进程所占用的虚拟内存大小。它包括进程可访问的所有虚拟内存空间,包括实际分配的内存、共享库、堆、栈和映射文件等。VIRT 指标可能会大于实际物理内存,因为它包括了未实际分配的虚拟内存空间
VIRT 包含 RES 的值
区别
meminfo
面板
cat /proc/meminfo----------------------------------------------------------------MemTotal: 3868864 kBMemFree: 140928 kBMemAvailable: 2456296 kBBuffers: 210416 kBCached: 2238404 kBSwapCached: 0 kBActive: 2546324 kBInactive: 941624 kBActive(anon): 1038396 kBInactive(anon): 1836 kBActive(file): 1507928 kBInactive(file): 939788 kBUnevictable: 0 kBMlocked: 0 kBSwapTotal: 0 kBSwapFree: 0 kBDirty: 1000 kBWriteback: 0 kBAnonPages: 1017048 kBMapped: 188840 kBShmem: 2216 kBKReclaimable: 144468 kBSlab: 195904 kBSReclaimable: 144468 kBSUnreclaim: 51436 kBKernelStack: 4352 kBPageTables: 10872 kBNFS_Unstable: 0 kBBounce: 0 kBWritebackTmp: 0 kBCommitLimit: 1934432 kBCommitted_AS: 2446620 kBVmallocTotal: 34359738367 kBVmallocUsed: 0 kBVmallocChunk: 0 kBPercpu: 1328 kBHardwareCorrupted: 0 kBAnonHugePages: 784384 kBShmemHugePages: 0 kBShmemPmdMapped: 0 kBHugePages_Total: 0HugePages_Free: 0HugePages_Rsvd: 0HugePages_Surp: 0Hugepagesize: 2048 kBHugetlb: 0 kBDirectMap4k: 171896 kBDirectMap2M: 4022272 kBDirectMap1G: 2097152 kB
复制代码
指标解释
重要指标
Committed_AS:目前在系统上分配的内存量。是所有进程申请的内存的总和
Slab:内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗
SReclaimable:可收回 Slab 的大小
PageTables:管理内存分页页面的索引表的大小
SLAB 是什么
内核为了高性能每个需要重复使用的对象都会有个池,这个 slab 池会 cache 大量常用的对象,所以会消耗大量的内存,他所消耗的内存是算在 free 命令中的 used 中还是在 cache 中呢?我们通过一组命令来确认
slabtop
#展示具体内核使用的内存的明细slabtop-------------------------------------------------------------------------------- Active / Total Objects (% used) : 3774607 / 4716484 (80.0%) Active / Total Slabs (% used) : 86026 / 86026 (100.0%) Active / Total Caches (% used) : 92 / 119 (77.3%) Active / Total Size (% used) : 678448.10K / 829043.07K (81.8%) Minimum / Average / Maximum Object : 0.01K / 0.17K / 14.09K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 2262372 2262372 100% 0.19K 53866 42 430928K dentry436224 417418 95% 0.03K 3408 128 13632K kmalloc-32401856 144870 36% 0.06K 6279 64 25116K kmalloc-64337920 105054 31% 0.02K 1320 256 5280K kmalloc-16269688 80643 29% 0.04K 2644 102 10576K selinux_inode_security137360 137360 100% 0.02K 808 170 3232K fsnotify_mark_connector126350 44070 34% 0.57K 2636 56 84352K radix_tree_node115712 110541 95% 0.01K 226 512 904K kmalloc-8 59920 55324 92% 0.21K 1621 37 12968K vm_area_struct 52952 14489 27% 0.94K 1568 34 50176K xfs_inode 52836 52836 100% 0.12K 777 68 6216K kernfs_node_cache 47872 39820 83% 0.25K 748 64 11968K kmalloc-256
--------------------------------------------------------------------------------#或者使用 cat /proc/slabinfo
--------------------------------------------------------------------------------# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>nf_conntrack_ffff8d47c7815200 2550 2550 320 51 4 : tunables 0 0 0 : slabdata 50 50 0nf_conntrack_ffff8d49b5e39480 306 306 320 51 4 : tunables 0 0 0 : slabdata 6 6 0nf_conntrack_ffff8d47c7813d80 2424 2652 320 51 4 : tunables 0 0 0 : slabdata 52 52 0nf_conntrack_ffff8d486c7f5200 2961 3366 320 51 4 : tunables 0 0 0 : slabdata 66 66 0nf_conntrack_ffff8d47c7812900 612 612 320 51 4 : tunables 0 0 0 : slabdata 12 12 0nf_conntrack_ffff8d49cbaebd80 306 306 320 51 4 : tunables 0 0 0 : slabdata 6 6 0nf_conntrack_ffff8d486a449480 306 306 320 51 4 : tunables 0 0 0 : slabdata 6 6 0nf_conntrack_ffff8d486a44bd80 2346 2346 320 51 4 : tunables 0 0 0 : slabdata 46 46 0nf_conntrack_ffff8d4877072900 2149 2346 320 51 4 : tunables 0 0 0 : slabdata 46 46 0nf_conntrack_ffff8d486a44e680 459 459 320 51 4 : tunables 0 0 0 : slabdata 9 9 0nf_conntrack_ffff8d486a44d200 2958 2958 320 51 4 : tunables 0 0 0 : slabdata 58 58 0nf_conntrack_ffff8d49cbaee680 306 306 320 51 4 : tunables 0 0 0 : slabdata 6 6 0nf_conntrack_ffff8d4877076680 255 255 320 51 4 : tunables 0 0 0 : slabdata 5 5 0nf_conntrack_ffff8d486a44a900 51 51 320 51 4 : tunables 0 0 0 : slabdata 1 1 0nf_conntrack_ffff8d49cbaed200 357 357 320 51 4 : tunables 0 0 0 : slabdata 7 7 0nf_conntrack_ffffffffba912940 2703 2703 320 51 4 : tunables 0 0 0 : slabdata 53 53 0--------------------------------------------------------------------------------
复制代码
PageTables
echo `grep PageTables /proc/meminfo | awk '{print $2}'`
复制代码
struct page 是系统 boot 的时候就会根据内存大小算出来分配出去的,18 内核是 1.56%左右,32 内核由于 cgroup 的原因会在 2.3%
单进程内存使用详情
cat /proc/PID/status------------------------------------------------------------------------------Name: mysqldUmask: 0026State: S (sleeping)Tgid: 6218Ngid: 0Pid: 6218PPid: 6201TracerPid: 0Uid: 999 999 999 999Gid: 999 999 999 999FDSize: 256Groups: NStgid: 6218 1NSpid: 6218 1NSpgid: 6218 1NSsid: 6218 1VmPeak: 1784400 kBVmSize: 1740884 kBVmLck: 0 kBVmPin: 0 kBVmHWM: 418632 kBVmRSS: 404556 kBRssAnon: 404556 kBRssFile: 0 kBRssShmem: 0 kBVmData: 806552 kBVmStk: 132 kBVmExe: 31092 kBVmLib: 0 kBVmPTE: 1168 kBVmSwap: 0 kB------------------------------------------------------------------------------
复制代码
进程直接内存的使用
#pmap命令可以查看进程的内存映射,包括堆外内存的使用量pmap -x PID----------------------------------------------------------------00000000f0000000 267776 155072 155072 rw--- [ anon ]0000000100580000 1042944 0 0 ----- [ anon ]000055c0b1b3b000 4 0 0 r-x-- java000055c0b1d3b000 4 4 4 r---- java000055c0b1d3c000 4 4 4 rw--- java000055c0b3499000 1696 1460 1460 rw--- [ anon ]00007f4fdeeb9000 12 0 0 ----- [ anon ]00007f4fdeebc000 1016 24 24 rw--- [ anon ]----------------------------------------------------------------cat /proc/PID/smaps----------------------------------------------------------------Size: 267776 kBKernelPageSize: 4 kBMMUPageSize: 4 kBRss: 155072 kBPss: 155072 kBShared_Clean: 0 kBShared_Dirty: 0 kBPrivate_Clean: 0 kBPrivate_Dirty: 155072 kBReferenced: 155072 kBAnonymous: 155072 kBLazyFree: 0 kBAnonHugePages: 153600 kBShmemPmdMapped: 0 kBShared_Hugetlb: 0 kBPrivate_Hugetlb: 0 kBSwap: 0 kBSwapPss: 0 kBLocked: 0 kBVmFlags: rd wr mr mw me ac sd 100580000-140000000 ---p 00000000 00:00 0
复制代码
AnonHugePages、Locked、RssAnon 等字段的行,它们提供了关于堆外内存的使用量的信息
不同维度的内存监控数据之间的关系
Committed_AS 包含了虚拟内存,所以 committed_AS 的值可能大于 free 命令中的 used 的值
VmRSS 表示当前实际驻留在物理内存中的内存大小,而 RES 表示进程当前使用的物理内存总量。两者之间的 关系是,VmRSS 是 RES 中的一个组成部分,两者相差不大,基本相同
free 中 used 的内存都去哪儿
通过该工具我们能看到内核使用的内存及用户态使用的内存
USED = use(用户态内存)+ Slab + PageTables
我们来做个实验
RSS 基本等于 VmRSS ,那我们通过 top 命令统计出所有的用户进程占用的物理内存
vi rss.sh------------------------------------------------------------#/bin/bash for PROC in `ls /proc/|grep "^[0-9]"`do if [ -f /proc/$PROC/statm ]; then TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'` RSS=`expr $RSS + $TEP` fidoneRSS=`expr $RSS \* 4`echo $RSS"KB"------------------------------------------------------------sh RSS.sh
复制代码
echo `cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'` MB
复制代码
echo `grep PageTables /proc/meminfo | awk '{print $2}'` KB
复制代码
通过上面的结论,当然数据上可能稍微有一些出入,特别是不同的 kernel 版本计算的方法可能存在一些差异,但是我们基本可以确定的是上述 used 的计算公式基本成立
解决方案
echo 3 > /proc/sys/vm/drop_caches
复制代码
讨论
JVM 内存设置参数中中通常有设置 xms 和 xmx,如果 xms=xmx ,那么如果 jvm 使用的物理内存没达到 xms 设置的值,used 中展示的是真实的内存使用值还是 xms 的值。如果是显示的是真实使用的物理内存的值,那么 xms 设置还有什么意义。怎么保证 jvm 在需要申请内存的时候有不少于 xms 的内存能够被申请到
如果大家感兴趣在下期分享
评论