今天讲一个排查问题的小故事吧.html
早上匆匆忙忙去上班了, 在一个例行的早会上, 意外被告知昨天 消息推送服务 内存报警, 超出了80%.bash
听完后不禁的虎躯一震, 由于从业务上和平常报警上是没有反馈的, 机器报警目前只报告给特定的运维团队, 而且距离此事情已通过去一段时间了.服务器
抱着侥幸的内心, 登陆到报警的机器上查看相关指标markdown
首先查看了下负载、业务进程和相关日志, 都没有错误日志记录, 也没有 OOM 被 kill 的记录.运维
既然是内存报警, 先重点看下内存占用状况函数
free -m
复制代码
能够看到空余内存仍是挺多的, 可是 Swap used保持在 149M 的占用, 证实了确实出现过内存不够使用的状况, 具体缘由先不探究, 咱们看下 swap 相关知识点.oop
思考一个问题, 当操做系统内存不够用的时会怎么办? 咱们知道磁盘通常被内存是廉价的, 而且存储容量是很大的. 最好的办法是将一部分当前不重要的数据放入磁盘来替代内存解燃眉之急.spa
其实,早期内存通常都比较小,很容易就出现内存不足的问题,因此很早就提出了一个交换分区(swap partition)的概念。操作系统
swap 分区是将磁盘看成内存使用,使得虚拟地址空间的范围大小能够超出物理内存的实际大小,在物理内存空间不足时,能够将物理内存中的一些不重要数据拷贝到磁盘的 swap 分区中,从而让出内存空间,而且在须要那些已被拷出数据时再从 swap 分区中拷回到内存,从而再也不那么容易发生OOM错误。.net
只有在出现物理内存耗尽或即将耗尽的时候,若是进程继续请求分配内存,将报错 out-of-memory(OOM)表示内存不足,而且在出现 OOM 的时候,操做系统将触发 OOM Killer 程序从进程列表中筛选出一个内存密集型进程杀掉,从而释放大片内存
介绍完 swap 概念, 咱们看下指定进程占用 swap 状况
#找到进程ID编号为 32132 cat /proc/32132/status 或 cat /proc/32132/smaps 复制代码
咱们核心的几个参数含义
VmPeak 进程所使用的虚拟内存的峰值
VmSize 进程当前使用的虚拟内存的大小
VmLck 已经锁住的物理内存的大小(锁住的物理内存不能交换到硬盘)
VmHWM 进程所使用的物理内存的峰值
VmRSS 进程当前使用的物理内存的大小
VmData 进程占用的数据段大小
VmStk 进程占用的栈大小
VmExe 进程占用的代码段大小(不包括库)
VmLib 进程所加载的动态库所占用的内存大小(可能与其它进程共享)
VmPTE 进程占用的页表大小(交换表项数量)
VmSwap 进程所使用的交换区的大小
复制代码
咱们能够看到此进程占用了 swap 交换区的 236kb
在上面参数含义中进程有虚拟内存、物理内存概念, 不知道你注意观察过没有, Top命令里也有 VIRT、RES、SHR相关的参数, 这是什么意思呢?
一、进程“须要的”虚拟内存大小,包括进程使用的库、代码、数据,以及malloc、new分配的堆空间和分配的栈空间等;
二、假如进程新申请10MB的内存,但实际只使用了1MB,那么它会增加10MB,而不是实际的1MB使用量。
三、VIRT = SWAP + RES
一、进程当前使用的内存大小,包括使用中的malloc、new分配的堆空间和分配的栈空间,但不包括swap out量;
二、包含其余进程的共享;
三、若是申请10MB的内存,实际使用1MB,它只增加1MB,与VIRT相反;
四、关于库占用内存的状况,它只统计加载的库文件所占内存大小。
五、RES = CODE + DATA
一、除了自身进程的共享内存,也包括其余进程的共享内存;
二、虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小;
三、计算某个进程所占的物理内存大小公式:RES – SHR;
四、swap out后,它将会降下来。
堆、栈分配的内存,若是没有使用是不会占用实存的,只会记录到虚存。若是程序占用实存比较多,说明程序申请内存多,实际使用的空间也多。若是程序占用虚存比较多,说明程序申请来不少空间,可是没有使用。工做中,遇到过有的程序虚存300G+, 实存只有不到15G。
了解了这些内存的概念后咱们在从新回到 swap 上面来, 上面咱们经过指定 pid 能够查看单个进程的 swap 占用状况, 我能够清理或者重启进程清理调 swap 占用, 可是我如何快速列出到底是哪些进程 swap 占用比较高呢.
查看占用 swap 排名前10的进程pid
for i in $(cd /proc;ls | grep "^[0-9]"|awk '$0 >100');do awk '/Swap:/{a=a+$2}END{print "'$i'", a/1024"M"}' /proc/$i/smaps 2>/dev/null;done | sort -k2nr | head -10 复制代码
通过重启清理后, 从新观察 swap 占用状况, 释放了部分空间
开启swap
# 含义为增长1G的交换分区, 文件大小= bs * count dd if=/dev/zero of=/root/swapfile bs=1M count=1024 mkswap /root/swapfile #创建swap的文件系统 swapon /root/swapfile #启用swap文件 复制代码
查看 swap 使用状况
swapon -s 或 cat /proc/swaps 复制代码
#关闭交换区 swapoff /root/swapfile #查看内存状况 free -m 复制代码
咱们发现 Swap 项所有变为了0, swapoff 能够不用重启进程快速释放交互区数据, 但存在的风险是数据是有可能丢失的.
#从新开启 swapon /root/swapfile #查看内存状况 free -m 复制代码