Linux内存泄露排查方案
/proc
文件系统
Linux的 /proc
文件系统包含了系统运行时的信息,包括每个进程的信息。可以通过查看 /proc/[pid]/status
文件来获取进程的内存使用信息。例如:
cat /proc/1234/status | grep VmSize
cat /proc/1234/status | grep VmRSS
-
VmSize
表示虚拟内存大小。 -
VmRSS
表示常驻集合大小,即实际使用的物理内存大小。
思路:就是每隔一段时间就收集一下各个进程物理内存的占用情况
check_VmRSS:
#!/bin/bash
# 指定使用bash shell执行本脚本check_vmrss()
{
# 定义名为check_vmrss的函数,用于检查进程内存使用情况date=`date`# 获取当前系统时间并存入date变量echo "$date" >> /cache/proc_vmrss.txt# 将当前时间追加写入/cache/proc_vmrss.txt文件ls /proc/ > /cache/proc_info.txt# 列出/proc目录内容并输出到/cache/proc_info.txt文件buddyinfo=`cat /proc/buddyinfo`# 读取/proc/buddyinfo文件内容存入buddyinfo变量echo "$buddyinfo">> /cache/proc_vmrss.txt# 将buddyinfo内容追加写入/cache/proc_vmrss.txtfor line in $(cat /cache/proc_info.txt); do# 开始循环读取proc_info.txt的每一行#echo $line# 调试用:打印当前行内容(注释状态)read -a array <<< "$line"# 将当前行内容按空格分割存入array数组PID=`echo ${array[-1]}`# 获取数组最后一个元素作为PID(进程ID)#echo $PID# 调试用:打印PID(注释状态)if [[ $PID =~ ^[0-9]+$ ]]; then# 检查PID是否为纯数字VmRSS=`cat /proc/$PID/status | grep VmRSS`# 获取该进程的VmRSS(实际物理内存使用量)Name=`cat /proc/$PID/status | grep Name`# 获取进程名称Pid=`cat /proc/$PID/status | grep "\<Pid"`# 获取进程ID(精确匹配Pid字段)if [ -n "$VmRSS" ]; then# 如果VmRSS不为空echo "$Name $Pid $VmRSS" >> /cache/proc_vmrss.txt# 将进程信息追加写入日志文件#printf "%-20s %-10s %-10s" $Name $Pid $VmRSS# 格式化输出(注释状态)#printf "%-20s" $Name#printf "%-10s" $Pid#printf "%-10s" $VmRSS#echo ""# 以上为调试用的格式化输出(均注释状态)fifidone# 结束for循环echo "" >> /cache/proc_vmrss.txt# 写入空行分隔不同时间点的记录
}
# 函数定义结束dates=`date +"%H:%M:%S"`
# 获取当前时间(时:分:秒格式)存入dates变量echo $dates
# 打印当前时间mv /cache/proc_vmrss.txt /cache/proc_vmrss_$dates.txt
# 重命名旧日志文件,添加时间戳后缀echo "start..." > /cache/proc_vmrss.txt
# 创建新日志文件并写入初始内容cnt=0
# 初始化循环计数器while [ true ]; do
# 开始无限循环let cnt=cnt+1# 计数器自增1echo "check cnt $cnt"# 打印当前循环次数check_vmrss# 调用check_vmrss函数检查内存sleep 5# 暂停5秒
done
# 循环结束
需要分析内存泄露问题,请通过/proc文件系统,写一个每隔10s采集各个进程物理内存占用情况的脚本,要求采集的信息包含进程名字,进程ID,进程物理内存的占用情况,而且需要按进程所占物理内存由大到小排序,并且每一行下面有英文注释
mem_monitor.sh:
#!/bin/bash
# Script to monitor process memory usage for leak detection
# Parameters: log path (default memory.log) and interval (default 10s)
LOG=${1:-memory.log}
INTERVAL=${2:-10}# Create temporary file for sorting
TMP_FILE=$(mktemp)# Write CSV header to log file
echo "Timestamp,ProcessName,PID,VmRSS(kB)" > $LOGwhile true; do# Clear temporary file for new data> $TMP_FILE# Get current timestamp in readable formatTIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')# Process all numeric directories in /proc (each represents a PID)for PID in $(ls /proc | grep -E '^[0-9]+$'); do# Check if process status file existsif [ -f /proc/$PID/status ]; then# Extract process name from Name: fieldNAME=$(grep -w 'Name:' /proc/$PID/status | awk '{print $2}')# Extract physical memory usage from VmRSS: field (in kB)RSS=$(grep -w 'VmRSS:' /proc/$PID/status | awk '{print $2}')# Write to temp file if memory value was obtained[ -n "$RSS" ] && echo "$TIMESTAMP,$NAME,$PID,$RSS" >> $TMP_FILEfidone# Sort by memory usage (4th column) in descending order and append to logsort -t, -k4 -nr $TMP_FILE >> $LOG# Add separator between each monitoring cycle in logecho "===== End of cycle =====" >> $LOG# Wait for specified interval before next scansleep $INTERVAL
done# Clean up temporary file on exit
trap "rm -f $TMP_FILE" EXIT