在Linux下,如何确定哪个进程在使用交换空间?
在Linux下,如何确定哪个进程在使用交换空间?
Answers:
运行顶部,然后按OpEnter。现在,应按进程的交换使用情况对其进行排序。
这是更新,因为我的原始答案并未提供评论中所指出问题的确切答案。从htop常见问题解答:
无法获得进程已使用交换空间的确切大小。Top通过使SWAP = VIRT-RES来伪造此信息,但这并不是一个很好的指标,因为其他内容(例如视频内存)也在VIRT上计数(例如:top说我的X进程正在使用81M交换,但是报告我的系统总体上仅使用2M交换。因此,我不会在htop中添加类似的Swap列,因为我不知道获取此信息的可靠方法(实际上,我认为不可能获得确切的数字,因为共享页面)。
我发现的最佳脚本在此页面上:http : //northernmost.org/blog/find-out-what-is-using-your-swap/
这是脚本的一种变体,不需要根目录:
#!/bin/bash
# Get current swap usage for all running processes
# Erik Ljungstrom 27/05/2011
# Modified by Mikko Rantalainen 2012-08-09
# Pipe the output to "sort -nk3" to get sorted output
# Modified by Marc Methot 2014-09-18
# removed the need for sudo
SUM=0
OVERALL=0
for DIR in `find /proc/ -maxdepth 1 -type d -regex "^/proc/[0-9]+"`
do
PID=`echo $DIR | cut -d / -f 3`
PROGNAME=`ps -p $PID -o comm --no-headers`
for SWAP in `grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'`
do
let SUM=$SUM+$SWAP
done
if (( $SUM > 0 )); then
echo "PID=$PID swapped $SUM KB ($PROGNAME)"
fi
let OVERALL=$OVERALL+$SUM
SUM=0
done
echo "Overall swap used: $OVERALL KB"
Overall swap used: 260672 KB
免费节目的738932
使用...
top
:Northernmost.org/blog/swap-usage-5-years-later
这是脚本的另一种变体,但其目的是提供更具可读性的输出(您需要以root用户身份运行此命令以获得准确的结果):
#!/bin/bash
# find-out-what-is-using-your-swap.sh
# -- Get current swap usage for all running processes
# --
# -- rev.0.3, 2012-09-03, Jan Smid - alignment and intendation, sorting
# -- rev.0.2, 2012-08-09, Mikko Rantalainen - pipe the output to "sort -nk3" to get sorted output
# -- rev.0.1, 2011-05-27, Erik Ljungstrom - initial version
SCRIPT_NAME=`basename $0`;
SORT="kb"; # {pid|kB|name} as first parameter, [default: kb]
[ "$1" != "" ] && { SORT="$1"; }
[ ! -x `which mktemp` ] && { echo "ERROR: mktemp is not available!"; exit; }
MKTEMP=`which mktemp`;
TMP=`${MKTEMP} -d`;
[ ! -d "${TMP}" ] && { echo "ERROR: unable to create temp dir!"; exit; }
>${TMP}/${SCRIPT_NAME}.pid;
>${TMP}/${SCRIPT_NAME}.kb;
>${TMP}/${SCRIPT_NAME}.name;
SUM=0;
OVERALL=0;
echo "${OVERALL}" > ${TMP}/${SCRIPT_NAME}.overal;
for DIR in `find /proc/ -maxdepth 1 -type d -regex "^/proc/[0-9]+"`;
do
PID=`echo $DIR | cut -d / -f 3`
PROGNAME=`ps -p $PID -o comm --no-headers`
for SWAP in `grep Swap $DIR/smaps 2>/dev/null| awk '{ print $2 }'`
do
let SUM=$SUM+$SWAP
done
if (( $SUM > 0 ));
then
echo -n ".";
echo -e "${PID}\t${SUM}\t${PROGNAME}" >> ${TMP}/${SCRIPT_NAME}.pid;
echo -e "${SUM}\t${PID}\t${PROGNAME}" >> ${TMP}/${SCRIPT_NAME}.kb;
echo -e "${PROGNAME}\t${SUM}\t${PID}" >> ${TMP}/${SCRIPT_NAME}.name;
fi
let OVERALL=$OVERALL+$SUM
SUM=0
done
echo "${OVERALL}" > ${TMP}/${SCRIPT_NAME}.overal;
echo;
echo "Overall swap used: ${OVERALL} kB";
echo "========================================";
case "${SORT}" in
name )
echo -e "name\tkB\tpid";
echo "========================================";
cat ${TMP}/${SCRIPT_NAME}.name|sort -r;
;;
kb )
echo -e "kB\tpid\tname";
echo "========================================";
cat ${TMP}/${SCRIPT_NAME}.kb|sort -rh;
;;
pid | * )
echo -e "pid\tkB\tname";
echo "========================================";
cat ${TMP}/${SCRIPT_NAME}.pid|sort -rh;
;;
esac
rm -fR "${TMP}/";
args
而不是comm
在ps
命令中使用,因为我有很多名称相同但参数不同的进程(一堆python gunicorn进程)。即:ps -p $PID -o args --no-headers
grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'
可以简化为awk ' /VmSwap/ { print $2 }'
我确实注意到该线程已经很旧了,但是,就像我刚才那样,如果您偶然发现了它,那么另一个答案是:使用smem。
这是一个告诉您如何安装和使用方法的链接:
http://www.cyberciti.biz/faq/linux-which-process-is-using-swap/
top命令还包含一个字段,以显示进程的页面错误数。具有最大页面错误的过程将是交换最多的过程。对于长时间运行的守护程序,可能是它们在开始时会引起大量的页面错误,而以后不会增加。因此,我们需要观察页面错误是否正在增加。
另一个避免在shell中循环的脚本变体:
#!/bin/bash
grep VmSwap /proc/[0-9]*/status | awk -F':' -v sort="$1" '
{
split($1,pid,"/") # Split first field on /
split($3,swp," ") # Split third field on space
cmdlinefile = "/proc/"pid[3]"/cmdline" # Build the cmdline filepath
getline pname[pid[3]] < cmdlinefile # Get the command line from pid
swap[pid[3]] = sprintf("%6i %s",swp[1],swp[2]) # Store the swap used (with unit to avoid rebuilding at print)
sum+=swp[1] # Sum the swap
}
END {
OFS="\t" # Change the output separator to tabulation
print "Pid","Swap used","Command line" # Print header
if(sort) {
getline max_pid < "/proc/sys/kernel/pid_max"
for(p=1;p<=max_pid;p++) {
if(p in pname) print p,swap[p],pname[p] # print the values
}
} else {
for(p in pname) { # Loop over all pids found
print p,swap[p],pname[p] # print the values
}
}
print "Total swap used:",sum # print the sum
}'
标准用法是script.sh
按随机顺序获取每个程序的用法(awk
取决于其散列的存储方式)或script.sh 1
按pid对输出进行排序。
我希望我已经对代码进行了足够的注释以说明其功能。
bash
以排序方式(词汇而非数字)扩展目录。随机顺序取决于如何awk
存储其数组(哈希表)以及如何for p in pname
检索它们。
/proc/1/status
随后,/proc/1992/status
并且/
在9个ascii代码之上都有一个ascii代码。这也给人一种“随机顺序”的感觉。我同意awk哈希表,我参加了一个快捷方式在这里可以随意编辑答案,以保持在归属编辑历史。
/proc/1/status
不会/proc/1992/status
在C语言环境中按字节值排序的顺序。它在您的语言环境(或在en_GB.UTF-8
GNU系统上的我的语言环境)中执行,因为/
在排序规则算法的第一个实例中将忽略该属性(并s
在之后排序9
)。printf '/proc/%s/status\n' 1 1992 | LC_ALL=en_GB.UTF-8 sort
与比较printf '/proc/%s/status\n' 1 1992 | LC_ALL=C sort
。在以外的语言环境中C
,排序顺序通常不基于字节值。
因为在小型系统上可能安装top
或htop
可能未安装,所以/proc
始终可以浏览。
即使在小型系统上,您也会发现shell
...
这正是比相同lolotux剧本,但没有任何叉grep
,awk
或ps
。这要快得多!
并作为 重击 是最穷的人之一 贝壳 关于性能,做了一些工作以确保该脚本在 短跑, 忙箱和其他一些。然后,(感谢StéphaneChazelas)再次变得更快了!
#!/bin/sh
# Get current swap usage for all running processes
# Felix Hauri 2016-08-05
# Rewritted without fork. Inspired by first stuff from
# Erik Ljungstrom 27/05/2011
# Modified by Mikko Rantalainen 2012-08-09
# Pipe the output to "sort -nk3" to get sorted output
# Modified by Marc Methot 2014-09-18
# removed the need for sudo
OVERALL=0
rifs=`printf ': \t'`
for FILE in /proc/[0-9]*/status ;do
SUM=0
while IFS="$rifs" read FIELD VALUE ;do
case $FIELD in
Pid ) PID=$VALUE ;;
Name ) PROGNAME="$VALUE" ;;
VmSwap ) SUM=$((SUM=${VALUE% *})) ;;
esac
done <$FILE
[ $SUM -gt 0 ] &&
printf "PID: %9d swapped: %11d KB (%s)\n" $PID $SUM "$PROGNAME"
OVERALL=$((OVERALL+SUM))
done
printf "Total swapped memory: %14u KB\n" $OVERALL
不要忘了双引号"$PROGNAME"
!请参阅StéphaneChazelas的评论:
read FIELD PROGNAME < <(
perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/status
)
echo $FIELD "$PROGNAME"
不要echo $PROGNAME
在明智的系统上使用双引号,并且准备在杀死当前的shell之前就做好准备!
由于这不是一个简单的脚本,因此需要时间来使用更高效的语言来编写专用工具。
#!/usr/bin/perl -w
use strict;
use Getopt::Std;
my ($tot,$mtot)=(0,0);
my %procs;
my %opts;
getopt('', \%opts);
sub sortres {
return $a <=> $b if $opts{'p'};
return $procs{$a}->{'cmd'} cmp $procs{$b}->{'cmd'} if $opts{'c'};
return $procs{$a}->{'mswap'} <=> $procs{$b}->{'mswap'} if $opts{'m'};
return $procs{$a}->{'swap'} <=> $procs{$b}->{'swap'};
};
opendir my $dh,"/proc";
for my $pid (grep {/^\d+$/} readdir $dh) {
if (open my $fh,"</proc/$pid/status") {
my ($sum,$nam)=(0,"");
while (<$fh>) {
$sum+=$1 if /^VmSwap:\s+(\d+)\s/;
$nam=$1 if /^Name:\s+(\S+)/;
}
if ($sum) {
$tot+=$sum;
$procs{$pid}->{'swap'}=$sum;
$procs{$pid}->{'cmd'}=$nam;
close $fh;
if (open my $fh,"</proc/$pid/smaps") {
$sum=0;
while (<$fh>) {
$sum+=$1 if /^Swap:\s+(\d+)\s/;
};
};
$mtot+=$sum;
$procs{$pid}->{'mswap'}=$sum;
} else { close $fh; };
};
};
map {
printf "PID: %9d swapped: %11d (%11d) KB (%s)\n",
$_, $procs{$_}->{'swap'}, $procs{$_}->{'mswap'}, $procs{$_}->{'cmd'};
} sort sortres keys %procs;
printf "Total swapped memory: %14u (%11u) KB\n", $tot,$mtot;
可以通过以下方式之一运行
-c sort by command name
-p sort by pid
-m sort by swap values
by default, output is sorted by status's vmsize
:
,,反斜杠,通配符或控制字符。
[1-9]
之前*
的只算编号路径(没有self
,也没有thread-self
)
Name
条目对/proc/*/status
其中一些字节值进行编码。例如尝试perl -ne 'BEGIN{$0="\n\t\\"} print if /^Name/' /proc/self/status
。因为它太短了,所以perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/status
当您忘记引用变量时,诸如此类的操作所造成的损害是有限的。
我在网上修改了一个不同的脚本来适应这一长线:
{ date;for f in /proc/[0-9]*/status; do
awk '{k[$1]=$2} END { if (k["VmSwap:"]) print k["Pid:"],k["Name:"],k["VmSwap:"];}' $f 2>/dev/null;
done | sort -n ; }
然后将其放入cronjob并将输出重定向到日志文件。此处的信息与累积Swap:
smaps文件中的条目相同,但是如果您想确定的话,可以使用:
{ date;for m in /proc/*/smaps;do
awk '/^Swap/ {s+=$2} END { if (s) print FILENAME,s }' $m 2>/dev/null;
done | tr -dc ' [0-9]\n' |sort -k 1n; }
此版本的输出分为两列:pid,交换金额。在上述版本中,这些tr
条去除了非数字部分。在这两种情况下,输出都按pid进行数字排序。
我想您可以通过运行top
并使用大量内存来查找活动进程来很好地猜测。以编程方式执行此操作比较困难-只需看看关于Linux OOM杀手启发法的无休止的辩论即可。
交换是在活动中拥有更多内存的功能使用的大于已安装的,因此通常很难将其归咎于单个进程。如果这是一个持续存在的问题,最好的解决方案是安装更多内存或进行其他系统更改。
这是一个输出与@loolotux脚本相同的版本,但是速度更快(虽然可读性较低)。该循环在我的计算机上花费大约10秒,我的版本花费0.019 s,这对我来说很重要,因为我想将其放入cgi页面。
join -t / -1 3 -2 3 \
<(grep VmSwap /proc/*/status |egrep -v '/proc/self|thread-self' | sort -k3,3 --field-separator=/ ) \
<(grep -H '' --binary-files=text /proc/*/cmdline |tr '\0' ' '|cut -c 1-200|egrep -v '/proc/self|/thread-self'|sort -k3,3 --field-separator=/ ) \
| cut -d/ -f1,4,7- \
| sed 's/status//; s/cmdline//' \
| sort -h -k3,3 --field-separator=:\
| tee >(awk -F: '{s+=$3} END {printf "\nTotal Swap Usage = %.0f kB\n",s}') /dev/null
自从2015年添加内核补丁SwapPss
(https://lore.kernel.org/patchwork/patch/570506/)以来,一个补丁最终可以按比例获得交换计数,这意味着如果一个进程交换了很多然后分叉,那么这两个分支进程将被报告每次交换50%。而且如果分叉,则每个进程都将计入已交换页面的33%,因此,如果将所有这些交换使用量一起计算,则将获得实际的交换使用量,而不是价值乘以进程计数。
简而言之:
(cd /proc; for pid in [0-9]*; do printf "%5s %6s %s\n" "$pid" "$(awk 'BEGIN{sum=0} /SwapPss:/{sum+=$2} END{print sum}' $pid/smaps)" "$(cat $pid/comm)"; done | sort -k2n,2 -k1n,1)
第一列是pid,第二列是KiB中的swap用法,其余的行是正在执行的命令。相同的交换计数按pid排序。
上面可能会发出诸如
awk: cmd. line:1: fatal: cannot open file `15407/smaps' for reading (No such file or directory)
这只是意味着进程号为15407的进程在查看列表/proc/
和读取进程smaps
文件之间结束。如果这对您很重要,只需添加2>/dev/null
到最后。请注意,您也可能会丢失任何其他可能的诊断信息。
在实际示例中,这会将其他工具报告为在一台服务器上运行的每个apache子级〜40 MB交换使用更改为每个子级实际使用的7-3630 KB的实际使用。