如何找出Linux中使用交换空间的进程?

时间:2009-01-26 14:29:58

标签: linux memory swap

在Linux下,如何找出更多使用交换空间的进程?

17 个答案:

答案 0 :(得分:283)

我找到的最佳脚本位于此页面:http://northernmost.org/blog/find-out-what-is-using-your-swap/

这是脚本的一个变体,不需要root:

#!/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"

答案 1 :(得分:100)

运行 top 然后按 O p 输入。现在,流程应按其交换使用情况进行排序。

这是一个更新,因为我的原始答案没有提供问题的确切答案,如评论中所指出的那样。来自htop FAQ

  

无法获得a的已使用交换空间的确切大小   处理。 Top通过制作SWAP = VIRT - RES来伪造这些信息,但是   这不是一个好的指标,因为其他东西,如视频内存   也依赖于VIRT(例如:top表示我的X进程正在使用   81M交换,但它也报告我的系统整体只使用2M   交换。因此,我不会在htop中添加类似的Swap列   因为我不知道获取这些信息的可靠方法(实际上,   由于共享,我认为不可能获得确切的数字   页)。

答案 2 :(得分:53)

这是脚本的另一个变体,但是意味着提供更可读的输出(您需要以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}/";

答案 3 :(得分:10)

如果您想要找到大多数页面被换出的流程或处理导致大多数页面被换出的流程,那么这一点并不完全清楚。

对于第一个,您可以运行top并按交换顺序(按'Op'),对于后者,您可以运行vmstat并查找'so'的非零条目。

答案 4 :(得分:9)

我确实注意到这个帖子已经很老了,但如果你偶然发现它,就像我刚才那样,另一个答案是:使用smem。

这是一个链接,告诉您如何安装它以及如何使用它:

http://www.cyberciti.biz/faq/linux-which-process-is-using-swap/

答案 5 :(得分:6)

top命令还包含一个字段,用于显示进程的页面错误数。具有最大页面错误的进程将是交换最多的进程。 对于长时间运行的守护进程,可能是它们在开始时出现大量页面错误,并且数字不会在以后增加。所以我们需要观察页面错误是否在增加。

答案 6 :(得分:6)

避免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对输出进行排序。

我希望我已经对代码进行了充分的评论,告诉它它的功能。

答案 7 :(得分:5)

还有两个变种:

变种! (不仅仅是打击)

这与lolotux script完全相同,但没有任何分支grepawkps。这要快得多!

由于是性能最差的之一,所以我们做了一些工作来确保此脚本在和其他一些项目下运行良好。然后,(thanks to Stéphane Chazelas,)再次变得更快!

#!/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éphane Chazelas's comment

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

答案 8 :(得分:2)

我想你可以通过运行top并使用大量内存查找活动进程来获得一个很好的猜测。以编程方式执行此操作更难 - 只需看看关于Linux OOM杀手启发式的无休止的争论。

交换是在活动中使用比安装更多内存的功能,因此通常很难将其归咎于单个进程。如果这是一个持续存在的问题,最好的解决方案是安装更多内存,或进行其他系统性更改。

答案 9 :(得分:2)

在MacOSX上,你也运行top命令,但需要输入“o”然后“vsize”然后输入。

答案 10 :(得分:2)

我在网上改编了一个不同的剧本,这个长篇单行:

 { 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并将输出重定向到日志文件。此处的信息与在smaps文件中累积Swap:条目相同,但如果您想确定,可以使用:

{ 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,swap amount。在上面的版本中,tr删除了非数字组件。在这两种情况下,输出都按pid进行数字排序。

答案 11 :(得分:1)

我不知道如何确切地找到使用交换空间的进程,但是,此链接可能是helpful。另一个好的是over here

另外,使用像htop这样的好工具来查看哪些进程正在使用大量内存以及使用了多少交换。

答案 12 :(得分:1)

使用交换

为流程提供总计和百分比
smem -t -p

enter image description here

来源:https://www.cyberciti.biz/faq/linux-which-process-is-using-swap/

答案 13 :(得分:1)

iotop是一个非常有用的工具。它提供每个进程/线程的I / O和交换使用的实时统计信息。默认情况下,它显示每个线程,但您可以iotop -P获取每个进程信息。默认情况下不可用。您可能必须通过rpm / apt安装。

答案 14 :(得分:0)

这是一个输出的版本与@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

答案 15 :(得分:0)

您可以使用Procpath(在此处作者)来简化对VmSwap/proc/$PID/status的解析。

$ procpath record -f stat,cmdline,status -r 1 -d db.sqlite
$ sqlite3 -column db.sqlite \
  'SELECT status_name, status_vmswap FROM record ORDER BY status_vmswap DESC LIMIT 5'
Web Content  192136       
okular       186872       
thunderbird  183692       
Web Content  143404       
MainThread   86300

您还可以像这样绘制VmSwap随时间变化的感兴趣的过程。在这里,我正在记录我的Firefox进程树,同时打开几十个选项卡,同时声明需要大量内存的应用程序以尝试使其进行交换(这对Firefox来说并不令人信服,但您的续航力可能会有所不同)。

$ procpath record -f stat,cmdline,status -i 1 -d db2.sqlite \
  '$..children[?(@.stat.pid == 6029)]'
# interrupt by Ctrl+C
$ procpath plot -d db2.sqlite -q cpu --custom-value-expr status_vmswap \
  --title "CPU usage, % vs Swap, kB"

CPU usage, % vs Swap, kB

答案 16 :(得分:0)

答案与@lolotux相同,但输出排序:

printf 'Computing swap usage...\n';
swap_usages="$(
    SUM=0
    OVERALL=0

    for DIR in `find /proc/ -maxdepth 1 -type d -regex "^/proc/[0-9]+"`
    do
        PID="$(printf '%s' "$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
            printf "$SUM KB ($PROGNAME) swapped PID=$PID\\n"
        fi
        let OVERALL=$OVERALL+$SUM
        SUM=0
        break
    done
    printf '9999999999 Overall swap used: %s KB\n' "$OVERALL"
)"

printf '%s' "$swap_usages" | sort -nk1

示例输出:

Computing swap usage...
2064 KB (systemd) swapped PID=1
59620 KB (xfdesktop) swapped PID=21405
64484 KB (nemo) swapped PID=763627
66740 KB (teamviewerd) swapped PID=1618
68244 KB (flameshot) swapped PID=84209
763136 KB (plugin_host) swapped PID=1881345
1412480 KB (java) swapped PID=43402
3864548 KB (sublime_text) swapped PID=1881327
9999999999 Overall swap used: 2064 KB