Linux内存解析
Linux内存解析系统内存我们在查看系统内存使用状况时,经常会常用free命令。下面是在一台centos物理机中执行free后的输出:# freetotalusedfreesharedbuff/cacheavailableMem: 1316353241227622010483626417600...
Linux内存解析
系统内存
我们在查看系统内存使用状况时,经常会常用free命令。下面是在一台centos物理机中执行free后的输出:
# free
total used free shared buff/cache available
Mem: 131635324 12276220 104836264 17600 14522840 117816640
Swap: 0 0 0
输出包括两行:Mem和Swap。其中Mem表示系统中实际的物理内存;Swap表示交换分区(类似windows中的虚拟内存),是硬盘中一个独立的分区,用于在系统内存不够时,临时存储被释放的内存空间中的内容。
上面的前三列"total"、“used”、"free"分别表示总量,使用量和有多少空闲空间。
对于Swap来说,三者的关系很简单,就是total = used + free。(在上面的例子中,由于这台主机禁用swap空间,所以swap的值都是0。)
对于Memory来说,我们发现total = used + free + buff/cache。其中buff和cache分别表示存放了将要写到磁盘中的数据和从磁盘的读取的数据的内存。也就是说内存除了存储进程运行所需的运行时数据之外,还为了提高性能,缓存了一部分I/O数据。
由于系统的cache和buffer可以被回收,所以可用的(available)内存比空闲的(free)要大。在部署了某些高I/O应用的主机中,available会比free看起来大很多,这是由于大量的内存空间用于缓存对磁盘的I/O数据。例如下面是在一台kafka服务器上执行free的结果(-g表示单位为GB):
# free -g
total used free shared buff/cache available
Mem: 125 38 10 0 77 84
free命令的所有输出值都是从/proc/meminfo中读出的
进程内存
通过free命令,我们可以看到系统总体的内存使用状况。但很多时需要查看特定进程(process)所消耗的内存,这时我们最常用的命令是ps,这个命令的输出中有两列与内存相关,分别是VSZ和RSS。此外还有另外两个类似的指标——PSS和USS,这里将这四个一并讨论:
缩写 | 全称 | 含义 |
---|---|---|
VSZ(VSS) | Virtual Memory Size | 虚拟内存大小,表明了该进程可以访问的所有内存,包括被交换的内存和共享库内存。VSZ对于判断一个进程实际占用的内存并没有什么帮助。 |
RSS | Resident Set Size | 常驻内存集合大小,表示相应进程在RAM中占用了多少内存,并不包含在Swap中占用的虚拟内存。包括进程所使用的共享库所占用的全部内存,即使某个共享库只在内存中加载了一次,所有使用了它的进程的RSS都会分别把它计算在内。(把所有进程的RSS加到一起,通常会比实际使用的内存大,因为一些共享库所用的内存被重复计算了多次。) |
PSS | Proportional Set Size | 与RSS类似,唯一的区别是在计算共享库内存是是按比例分配。比如某个共享库占用了3兆内存,同时被3个进程共享,那么在计算这3个进程的PSS时,该共享库这会贡献1兆内存。 |
USS | Unique Set Size | 进程独自占用的物理内存,不包含Swap和共享库。 |
一幅图胜过千言万语:
可以看到,这四者的大小关系是:VSS >= RSS >= PSS >= USS
进程的内存使用情况可以从/proc/PID/status中读取,比如
- VmSize: 当前的Virtual Memory Size
- VmRSS: Resident Set Size
- VmLib:进程所加载的动态库所占用的内存大小
容器内存
接下来看一下在docker中如何获得容器的内存使用状况。容器是系统内核所提供的一种进程级虚拟化机制,实现了各个进程间的资源隔离。
一个最自然的想法就是进入一个容器内部,执行free命令:
# free -g
total used free shared buff/cache available
Mem: 125 38 10 0 77 84
结果输出的是宿主机内存信息。显然这样不行。
查看容器中的主进程(PID = 1)的/proc/1/status,显示的内容包括进程的VSS和RSS,这个没有问题。
在遵循one docker one process的原生容器中,主进程基本反应了容器的内存使用状况,但这毕竟不完整,况且一个容器中运行多个进程的情况也很常见。因而需要一种更优雅的容器内存查看方式,那就是cgroup。
cgroup是Linux内核提供的一种限制和查询一组进程资源使用的功能,docker用它实现了对容器可用资源的限制。一个容器的某类资源(例如:内存)对应系统中一个cgroup子系统(subsystem) hierachy中的节点(例如/sys/fs/cgroup/memory/docker下的子目录)。在这个目录中有很多文件提供了容器对系统资源使用状况的信息。比如:memory.stat文件包含了容器的内存状况:
# cat memory.stat
cache 12288
rss 57253888
rss_huge 8388608
mapped_file 0
swap 0
pgpgin 44462
pgpgout 39168
pgfault 77640
pgmajfault 0
inactive_anon 0
active_anon 57253888
inactive_file 0
active_file 12288
unevictable 0
hierarchical_memory_limit 9223372036854771712
hierarchical_memsw_limit 9223372036854771712
total_cache 12288
total_rss 57253888
total_rss_huge 8388608
total_mapped_file 0
total_swap 0
total_pgpgin 44462
total_pgpgout 39168
total_pgfault 77640
total_pgmajfault 0
total_inactive_anon 0
total_active_anon 57253888
total_inactive_file 0
total_active_file 12288
total_unevictable 0
在上面的文件中,重点关注cache和rss
- cache - # of bytes of page cache memory.
- rss - # of bytes of anonymous and swap cache memory (includes
transparent hugepages).
在Linux内核中,对于进程的内存使用与Cgroup的内存使用统计有一些相同和不同的地方:
- 进程的RSS为进程使用的所有物理内存,不包含Swap,包含共享内存;cgroup RSS包含Swap,不包含共享内存。(因而,在没有swap的情况下,cgroup的RSS更像是进程的USS)
- 两者都不包含文件cache。
- cgroup cache包含文件cache和共享内存。
Google的容器内存监控工具cAdvisor就是通过读取cgroup信息来获取容器的内存使用信息。其中有一个监控指标container_memory_usage_bytes(Current memory usage in bytes, including all memory regardless of when it was accessed),如果只看名字和注解,很自然就认为它是容器所使用的内存。但是你可能会发现,如果不设置内存上限,某些容器的这个值出奇的大。原因就在于这里所谓的usage和通过free指令输出的used memory的含义是不同的,前者实际上是cgroup的rss和cache的和,而后者不包含cache。
结论:
就像进程的USS最准确的反映了进程自身使用的内存,cgroup的RSS也最真实的反映了容器所占用的内存空间。
更多推荐
所有评论(0)