记录一次内存问题排查
查看内存使用量
free -h
在日常运维中,-h -g是常用的参数
-g:以千兆字节(GB)为单位显示内存信息
-h:以人类可读的格式显示内存信息(自动选择合适的单位)
total:总内存量
used:已使用的内存量,包括了当前正在使用的内存和内核缓存的内存
free:空闲的内存量
shared:进程间共享的内存量
buff/cache:内核缓冲区和缓存的内存量
available:可供新进程使用的内存量
对于现代 Linux 系统,shared值通常较小,可以忽略,因此主要关注used,free,buffer,以及available的值,将总内存拆解成已使用和未使用进行进一步分析。
针对未使用的内存
free 指代的是物理内存中没有被使用的部分,available考虑了内核可以回收的缓存和缓冲区,并且比 free 更加准确地反映了可以立即使用的内存量,通常情况下可以将操作系统可用内存近似理解成空闲内存和缓存之和。然而,在本次问题场景下,出现内存占用中 available 的值远小于 free,查阅资料了解到available的内存计算公式,由free,cache,LowWaterMark三个参数共同影响。
MemAvailable = MemFree - LowWaterMark + (Cache - min(Cache / 2, LowWaterMark))
这里引入了一个内存水位的概念,LowWaterMark指的就是低水位内存。
内存水位通常用于描述操作系统中内存管理的机制,尤其是在 Linux 内核中。内存水位的概念帮助内核决定何时开始采取特定的内存管理动作,以确保系统有足够的可用内存并避免内存耗尽的情况。
在 Linux 内核中,内存水位有三个主要级别:
- min(最小水位):内存的最低水位,达到这个水位意味着系统的内存非常低,内核必须立即采取紧急措施来回收内存;这通常涉及停止分配新的内存并开始回收缓存和交换内存。
- low(低水位):内存的低水位,达到这个水位时,内核会启动后台进程来回收内存,但不会影响前台任务的正常运行;系统会积极回收缓存和释放内存,但仍会允许内存分配请求。
- high(高水位):内存的高水位,只要内存可用量高于这个水位,系统就认为内存情况正常,不需要采取任何特殊的内存回收措施;此时,内核将允许内存分配请求而不会启动额外的内存回收进程。
内存水位(min、low、high)的具体计算是在内核源码中进行的,主要涉及到 calculate_min_free_kbytes 和 setup_per_zone_lowmem_reserve 等函数,可以通过调整 min_free_kbytes 值,从而间接调整 low 和 high 水位(具体三个水位之间的数量关系此处略过)。
在 Linux 内核中,物理内存被划分为不同的内存区域(zones):
- DMA:用于 DMA(Direct Memory Access)设备的内存区域。
- DMA32:用于 32 位地址设备的内存区域。
- Normal:正常内存区域,用于一般用途。
- HighMem:高内存区域,仅在 32 位系统中存在,用于高于 4GB 的内存。
lowmem_reserve_ratio 定义了各内存区域之间的内存保留比例,该参数确保高优先级的内存区域不会被低优先级的任务完全耗尽,可以在 /proc/sys/vm/lowmem_reserve_ratio 进行查看。
在计算内存水位时,需要先将各个区域的内存页数相加,乘上页面大小,即可得到内存水位的大小,对于最小水位,也可直接查看。
举个例子,下图中,低内存水位页数为7448+33510,页面大小为64kb,求得低内存水位约为2.5g
根据 available 内存计算公式计算得 3.3-2.5+5.4-min(2.7,2.5)= 3.7g,与显示的3.1g相差不大
ps:具体误差0.6 可能是公式有更细粒度的参数没有标注,或内存数截断有影响等,大致符合预期即可,更精确的计算结果可以去查阅linux源码
# 查看内存水位页数
cat /proc/zoneinfo | grep -E 'min|low|high'
# 查看页面大小
getconf PAGE_SIZE
# 直接查看最小水位大小
cat /proc/sys/vm/min_free_kbytes
由于内存水位的值设置的过大,导致空闲的内存无法被新进程使用,导致出现了 free 较大而 available 较小的现象,此时可以适当调整最小内存水位的值,从而降低低内存水位,在不对 used 内存做缩减时,提高 available 的值。
vi /etc/sysctl.conf
# 添加以下内容
vm.min_free_kbytes = xx
# 退出文档编辑,使参数配置生效
sysctl -p
再次查看内存,发现 available 可用内存已得到扩展。
一般操作系统的内存水位默认值已经是合理范围,除非之前有人工修改过或对linux参数熟练掌握,否则不建议去修改。
针对已使用的内存
top 查看内存占用,找出内存占用最大的进程,进一步排查应用使用情况
以数据库为例,发现数据库占用内存较大时,可以查看数据库的基本使用情况(实际数据库内存调优有多种方法,本文简单介绍,不做扩展)
- 查看当前活跃会话,判断是否有异常sql,若存在,则要针对sql执行策略或者执行计划做进一步判断
- 查看数据库的内存参数限制,是否需要调整
…