How to find out which processes are using swap space in Linux?

后端 未结 18 1880
终归单人心
终归单人心 2020-11-27 09:11

Under Linux, how do I find out which process is using the swap space more?

相关标签:
18条回答
  • 2020-11-27 09:14

    I adapted a different script on the web to this long one-liner:

     { 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 ; }
    

    Which I then throw into a cronjob and redirect output to a logfile. The information here is the same as accumulating the Swap: entries in the smaps file, but if you want to be sure, you can use:

    { 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; }
    

    The output of this version is in two columns: pid, swap amount. In the above version, the tr strips the non-numeric components. In both cases, the output is sorted numerically by pid.

    0 讨论(0)
  • 2020-11-27 09:15

    Yet two more variants:

    Because top or htop could be not installed on small systems, browsing /proc stay always possible.

    Even on small systems, you will found a shell...

    A shell variant! (Not bash only)

    This is exactly same than lolotux script, but without any fork to grep, awk or ps. This is a lot quicker!

    And as bash is one of the poorest shell regarding performance, a little work was done to ensure this script will run well under dash, busybox and some other. Then, (thanks to Stéphane Chazelas,) become a lot quicker again!

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

    Don't forgot to double quote "$PROGNAME" ! See Stéphane Chazelas's comment:

    read FIELD PROGNAME < <(
        perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/status
    )
    echo $FIELD "$PROGNAME"
    

    Don't try echo $PROGNAME without double quote on sensible system, and be ready to kill current shell before!

    And a perl version

    As this become a not so simple script, time is comming to write a dedicated tool by using more efficient language.

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

    could by run with one of

    -c  sort by command name
    -p  sort by pid
    -m  sort by swap values
    by default, output is sorted by status's vmsize
    
    0 讨论(0)
  • 2020-11-27 09:15

    Here's a version that outputs the same as the script by @loolotux, but is much faster(while less readable). That loop takes about 10 secs on my machine, my version takes 0.019 s, which mattered to me because I wanted to make it into a cgi page.

        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
    
    0 讨论(0)
  • 2020-11-27 09:16

    Run top then press OpEnter. Now processes should be sorted by their swap usage.

    Here is an update as my original answer does not provide an exact answer to the problem as pointed out in the comments. From the htop FAQ:

    It is not possible to get the exact size of used swap space of a process. Top fakes this information by making SWAP = VIRT - RES, but that is not a good metric, because other stuff such as video memory counts on VIRT as well (for example: top says my X process is using 81M of swap, but it also reports my system as a whole is using only 2M of swap. Therefore, I will not add a similar Swap column to htop because I don't know a reliable way to get this information (actually, I don't think it's possible to get an exact number, because of shared pages).

    0 讨论(0)
  • 2020-11-27 09:16

    Since the year 2015 kernel patch that adds SwapPss (https://lore.kernel.org/patchwork/patch/570506/) one can finally get proportional swap count meaning that if a process has swapped a lot and then it forks, both forked processes will be reported to swap 50% each. And if either then forks, each process is counted 33% of the swapped pages so if you count all those swap usages together, you get real swap usage instead of value multiplied by process count.

    In short:

    (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)
    

    First column is pid, second column is swap usage in KiB and rest of the line is command being executed. Identical swap counts are sorted by pid.

    Above may emit lines such as

    awk: cmd. line:1: fatal: cannot open file `15407/smaps' for reading (No such file or directory)
    

    which simply means that process with pid 15407 ended between seeing it in the list for /proc/ and reading the process smaps file. If that matters to you, simply add 2>/dev/null to the end. Note that you'll potentially lose any other possible diagnostics as well.

    In real world example case, this changes other tools reporting ~40 MB swap usage for each apache child running on one server to actual usage of between 7-3630 KB really used per child.

    0 讨论(0)
  • 2020-11-27 09:17

    On MacOSX, you run top command as well but need to type "o" then "vsize" then ENTER.

    0 讨论(0)
提交回复
热议问题