linux内存问题排查记录

记录一次内存问题排查

查看内存使用量

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 查看内存占用,找出内存占用最大的进程,进一步排查应用使用情况

以数据库为例,发现数据库占用内存较大时,可以查看数据库的基本使用情况(实际数据库内存调优有多种方法,本文简单介绍,不做扩展)

  1. 查看当前活跃会话,判断是否有异常sql,若存在,则要针对sql执行策略或者执行计划做进一步判断
  2. 查看数据库的内存参数限制,是否需要调整
Linux 内存泄漏排查的方法有很多种,这里介绍一些常用的方法: 1. 使用 Valgrind 工具:Valgrind 是一个强大的开源工具集,可以用来检测内存泄漏、越界访问、使用未初始化的内存问题。使用 Valgrind 工具可以非常方便地发现内存泄漏问题,具体使用方法如下: ```bash valgrind --leak-check=full ./your_program ``` 这条命令会在运行你的程序时启动 Valgrind 工具,并检查程序中的内存泄漏问题。Valgrind 工具会输出详细的检查结果,包括内存泄漏的位置、大小等信息。 2. 使用 GNU glibc 内存泄漏检测:GNU glibc 是 Linux 系统中常用的 C/C++ 库,它提供了一些内存泄漏检测的函数。具体使用方法如下: ```c++ #include <mcheck.h> int main(int argc, char* argv[]) { mtrace(); // your code here muntrace(); return 0; } ``` 这段代码会在程序启动时调用 `mtrace()` 函数,启用内存泄漏检测功能。在程序结束时,调用 `muntrace()` 函数来关闭检测功能。通过这种方法,可以在程序运行时检查内存泄漏问题,并输出相应的检测结果。 3. 手动检查代码:手动检查代码是一种比较耗时、费力的方法,但是可以帮助程序员深入了解程序的内部实现。具体方法是,在程序中添加日志输出或者调试信息,记录每个内存分配和释放的位置、大小等信息,然后分析这些信息来确定是否存在内存泄漏问题。 需要注意的是,内存泄漏只是 Linux 内存管理中的一个问题,还有很多其他问题也需要注意,比如内存越界访问、使用未初始化的内存问题。因此,在开发程序时,应该注意遵循良好的编程习惯,确保程序的健壮性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值