了解系统的内存消耗是运维最基本的技能,但是Linux中关于内存消耗的指标很容易让人混淆,本文尝试把诸多概念解释清楚
概念
物理内存和虚拟内存
物理内存:不解释;虚拟内存:进程独享,由操作系统通过地址映射的方式,转换为对物理内存的访问。在32位Linux机器上,每个进程的虚拟内存都是4G。(这里的虚拟内存与操作系统使用中过程常见的虚拟内存概念不同,不要混淆了,如Linux中swap)
内存耗用指标
- VSS – Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
- RSS – Resident Set Size 实际使用物理内存(包含共享库占用的内存)
- PSS – Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
- USS – Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
TOP命令
top - 21:58:44 up 4:45, 3 users, load average: 2.57, 1.72, 0.75 Tasks: 108 total, 1 running, 107 sleeping, 0 stopped, 0 zombie %Cpu(s): 5.9 us, 5.9 sy, 0.0 ni, 88.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 1865252 total, 542664 free, 459884 used, 862704 buff/cache KiB Swap: 2097148 total, 2097148 free, 0 used. 1144688 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 127936 6576 4128 S 0.0 0.4 0:01.33 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root 20 0 0 0 0 S 0.0 0.0 0:00.63 ksoftirqd/0 5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
- VIRT(Virtual memory space) - 这里是虚拟内存(进程地址空间),包括数据、代码、堆、共享库、内存映射文件等,可以使用
pmap
命令查看详情。并不是真实内存耗费,比如我们可以通过命令java -Xms1024m -Xmx40960m Hello
就可以得到VIRT为41G的进程。 - RES(Resident set size) - 实际使用的物理内存(包含共享库占用的内存),与RSS相同
- SHR - 与其他进程共享的内存
PS命令
$ ps aux | head USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.3 127936 6576 ? Ss 17:12 0:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 22 root 2 0.0 0.0 0 0 ? S 17:12 0:00 [kthreadd]
SMEM命令
smem
命令可以得到USS, PSS,更能反映进程的真实内存消耗
$ smem PID User Command Swap USS PSS RSS 111965 root -bash 0 504 757 2164 113696 root -bash 0 512 779 2200 1553 root -bash 0 516 783 2204 10556 root top 0 868 968 2292 18799 root python /usr/bin/smem 0 4712 5169 6892 112580 root java -Xms1024m -Xmx40960m A 0 31036 31076 32040
注意事项
- top命令中res与ps命令rss大小一致,数据都是来自
/proc/{pid}/status
- pmap与smem中的rss大小一致,数据来自
/proc/{pid}/maps
- 但是以上两个数据却不一致,可能的原因如下:
man ps
得到以下解释:
The SIZE and RSS fields don't count some parts of a process including the page tables, kernel stack, struct thread_info, and struct task_struct. This is usually at least 20 KiB of memory that is always resident. SIZE is the virtual size of the process (code+data+stack).
实践
- 不用考虑VIRT耗费情况
- 一般也不要考虑RES内存消耗,除非一直在增大,则说明可能存在内存泄露
- 如果系统开始出现SWAP,就需要解决RES占用过多的问题