我们发现“提交”随着时间的推移出现了“泄漏”,需要跟踪有问题的进程。RSS(“已用”内存”)没有泄漏,但提交有泄漏,这导致内核行为非常糟糕(当提交百分比达到 ~ 200% 时无法分配内存)。我知道我们可以使用 /proc/sys/vm/overcommit_memory 来调整它,但这不是重点 - 我们想找到泄漏的进程。
我已尝试从 etc/(proc)/smap 和 dmap 进行各种计算,但是所有进程中没有任何内容与 /proc/meminfo 中的提交类似。 https://www.kernel.org/doc/Documentation/vm/overcommit-accounting非常模糊,我不清楚如何使用它。
有什么建议么?
答案1
发布内容是为了提供我们如何解决这个问题 - 并不优雅或精致,也不是直接的答案(我们没有获得进程的实际过度提交分配),但我们确定了罪魁祸首并发现了一个微妙的内存泄漏。
对于没有评论等,请多多包涵,但这些都是快速使用的工具。有了它...
我们查看了pmap
命令结果和进程数据扫描/etc/<pid>/smaps
,汇总了同一进程的副本,然后将其加载到电子表格中进行分析。我们在一周内每天拍摄几次快照,并查看了内存使用趋势。这向我们展示了具有相同名称的一组进程的内存随时间变化的趋势,这使我们能够识别有问题的进程集。
控制脚本(运行一组命令并将结果组织在一个文件中)
gpmemstatFile=gpmemstat.$(日期“+%F.%H.%M.%S.%N”| cut -c 1-23) echo '--------------------------------------------------------' >> $gpmemstatFile echo $(主机名) >> $gpmemstatFile echo $(日期) >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile echo >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile echo ‘/proc/meminfo’ >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile cat /proc/meminfo >> $gpmemstatFile echo >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile 回显‘sar -r’>>$gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile sar -r >> $gpmemstat文件 echo >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile 回显‘sar -R’>>$gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile sar -R >> $gpmemstat文件 echo >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile echo ‘gpsmapstat (/proc/(pid)/smaps 聚合)’ >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile gpsmapsstat httpd oninit fglrun java fastcgi gdcproxy >> $gpmemstatFile echo >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile echo ‘gppmapstat (pmap -d -x 聚合)’ >> $gpmemstatFile echo '--------------------------------------------------------' >> $gpmemstatFile gppmapstat httpd oninit fglrun java fastcgi gdcproxy >> $gpmemstatFile 如果 [ -n "$1" ]; 那么 scp $gpmemstat文件$1 菲
该脚本用于收集pmap
特定名称的所有进程的进程数据(您可以使用其他机制来识别要分析的进程)。它汇总了某一类型的所有进程的总内存使用量。
printf "%8s %8s %8s %8s %8s %8s %8s %8s\n" name PID Total Resident Dirty Private Shared Unshared
for name in $@ ; do
unset sumTotalMemory sumResidentMemory sumDirtyMemory sumPrivateMemory sumSharedMemory sumUnsharedMemory
for pid in $( ps aux | grep $name | awk '{print $2}') ; do
xMemory=$(pmap -x $pid | tail -1)
totalMemory=$(echo $xMemory | awk '{print $3}')
if [ -n "$totalMemory" ] ; then sumTotalMemory=$(($sumTotalMemory + $totalMemory)) ; fi
residentMemory=$(echo $xMemory | awk '{print $4}')
if [ -n "$residentMemory" ] ; then sumResidentMemory=$(($sumResidentMemory + $residentMemory)) ; fi
dirtyMemory=$(echo $xMemory | awk '{print $5}')
if [ -n "$dirtyMemory" ] ; then sumDirtyMemory=$(($sumDirtyMemory + $dirtyMemory)) ; fi
dMemory=$(pmap -d $pid | tail -1)
privateMemory=$(echo $dMemory | awk '{print $4}')
if [ -n "$privateMemory" ] ; then
privateMemory=${privateMemory:0:${#privateMemory}-1}
sumPrivateMemory=$(($sumPrivateMemory + $privateMemory))
fi
sharedMemory=$(echo $dMemory | awk '{print $6}')
unset unsharedMemory
if [ -n "$sharedMemory" ] ; then
sharedMemory=${sharedMemory:0:${#sharedMemory}-1}
sumSharedMemory=$(($sumSharedMemory + $sharedMemory ))
unsharedMemory=$(($totalMemory - $sharedMemory))
sumUnsharedMemory=$(( $sumUnsharedMemory + $unsharedMemory ))
fi
#printf "%8s %8s %8s %8s %8s %8s %8s %8s\n" $name $pid $totalMemory $residentMemory $dirtyMemory $privateMemory $sharedMemory $unsharedMemory
done
if [ -n "$sumTotalMemory" ] ; then
printf "%8s %8s %8s %8s %8s %8s %8s %8s\n" $name Total $sumTotalMemory $sumResidentMemory $sumDirtyMemory $sumPrivateMemory $sumSharedMemory $sumUnsharedMemory
printf "%8s %8s %8s %8s %8s %8s %8s %8s\n" $name MiB $(($sumTotalMemory/1024)) $(($sumResidentMemory/1024)) $(($sumDirtyMemory/1024)) $(($sumPrivateMemory/1024)) $(($sumSharedMemory/1024)) $(($sumUnsharedMemory/1024))
printf "%8s %8s %8s %8s %8s %8s %8s %8s\n" $name GiB $(echo "scale=2; $sumTotalMemory/1024/1024" | bc) $(echo "scale=2; $sumResidentMemory/1024/1024" | bc) $(echo "scale=2; $sumDirtyMemory/1024/1024" | bc) $(echo "scale=2; $sumPrivateMemory/1024/1024"| bc) $(echo "scale=2; $sumSharedMemory/1024/1024"| bc) $(echo "scale=2; $sumUnsharedMemory/1024/1024"| bc)
fi
done
该脚本查看所有proc/<pid>/smaps
文件,并汇总特定名称的所有进程的内存数据(同样,您可以使用其他机制来识别要分析的进程)。这再次总结了某一类型的所有进程的内存使用总量。
printf "%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n" name size rss pss shrdCln shrdDrty prvtCln prvtDrty refrncd swap
for name in $*; do
unset awkFiles
for pid in $( ps aux | grep $name | awk '{print $2}') ; do
if [ -e /proc/$pid/smaps ] ; then
awkFiles=${awkFiles}" /proc/$pid/smaps"
fi
done
if [ -n "$awkFiles" ] ; then
awk -v name="$name" '{
if ($1 == "Size:" ){
sizeSum+=$2
}
else if ($1 == "Rss:" ){
rssSum+=$2
}
else if ($1 == "Pss:" ){
pssSum+=$2
}
else if ($1 == "Shared_Clean:" ){
sharedCleanSum+=$2
}
else if ($1 == "Shared_Dirty:" ){
sharedDirtySum+=$2
}
else if ($1 == "Private_Clean:" ){
privateCleanSum+=$2
}
else if ($1 == "Private_Dirty:" ){
privateDirtySum+=$2
}
else if ($1 == "Referenced:" ){
referencedSum+=$2
}
else if ($1 == "Swap:" ){
swapSum+=$2
}
}
END { printf "%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n", name, sizeSum, rssSum, pssSum, sharedCleanSum, sharedDirtySum, privateCleanSum, privateDirtySum, referencedSum, swapSum}' $awkFiles
fi
done
再次,并不完善,也不是实际的答案(我仍然不知道如何获取内存提交电荷排序列表中的进程),但它在这里确实起了作用。
答案2
我不确定我是否正确理解了你的问题,但首先我想找出实际内存使用情况以及实际共享内存。请使用下面提到的 python 脚本
https://raw.githubusercontent.com/pixelb/ps_mem/master/ps_mem.py
希望这会有所帮助或迈出调试的第一步......