如何找出Linux中哪些进程正在使用交换空间?

如何找出Linux中哪些进程正在使用交换空间?,linux,memory,swap,shell,bash,dash,busybox,perl,Linux,Memory,Swap,Shell,Bash,Dash,Busybox,Perl,在Linux下,如何找出哪个进程更多地使用交换空间?我想您可以通过运行top并查找使用大量内存的活动进程来进行猜测。通过编程实现这一点更难——只要看看关于Linux OOM杀手启发法的无休止的争论就知道了 交换是一种主动使用的内存多于已安装内存的功能,因此通常很难将其归咎于单个进程。如果这是一个持续存在的问题,最好的解决方案是安装更多内存,或进行其他系统性更改。我不知道如何准确找到使用交换空间的进程的任何直接答案,但是,这个链接可能是。另一个好的是 另外,请使用诸如htop之类的好工具查看哪些进

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

我想您可以通过运行
top
并查找使用大量内存的活动进程来进行猜测。通过编程实现这一点更难——只要看看关于Linux OOM杀手启发法的无休止的争论就知道了


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

我不知道如何准确找到使用交换空间的进程的任何直接答案,但是,这个链接可能是。另一个好的是

另外,请使用诸如htop之类的好工具查看哪些进程占用了大量内存,以及使用了多少总交换量。

运行top,然后按OpEnter。现在,进程应该按其交换使用情况进行排序

这里是一个更新,因为我的原始答案没有提供一个准确的答案,如在评论中指出的问题。从:

无法获得已使用的交换空间的确切大小 过程Top通过SWAP=VIRT-RES伪造此信息,但是 这不是一个好的指标,因为其他东西,比如视频内存 也依赖于VIRT(例如:top说我的X进程正在使用 8100万次交换,但它也报告说我的系统总体上只使用了200万次交换 因此,我不会在htop中添加类似的交换列 因为我不知道获得这些信息的可靠方法(实际上, 我认为不可能得到一个确切的数字,因为共享的数据 页数)


还不完全清楚您的意思是要查找交换了最多页面的进程还是导致交换了最多页面的进程


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

我找到的最佳脚本位于此页:

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

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

在MacOSX上,您也可以运行top命令,但需要先键入“o”,然后键入“vsize”,然后输入。

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

这里是脚本的另一个变体,但其目的是提供更具可读性的输出(您需要以root用户身份运行此脚本以获得准确的结果):

使用


这里有一个链接,告诉您如何安装和如何使用它:

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

另一个避免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
  }'
!/bin/bash
grep VmSwap/proc/[0-9]*/status | awk-F':'-v sort=“$1”
{
拆分($1,pid,“/”)#拆分上的第一个字段/
拆分($3,swp,“”)#拆分空间上的第三个字段
cmdlinefile=“/proc/”pid[3]”/cmdline“#构建cmdline文件路径
getline pname[pid[3]对于(p=1;p1),我在web上使用了不同的脚本来适应这个长的一行:

 { 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文件中累积
交换:
项相同,但如果您想确定,可以使用:

{ 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
htop
,因此浏览
/proc
始终是可能的

即使在小型系统上,您也会发现一个
shell

一个变体!(不仅仅是bash) 这与完全相同,但没有任何指向
grep
awk
ps
的分支。这比快得多!

作为性能最差的脚本之一,我们做了一些工作来确保这个脚本能够在其他脚本下正常运行。然后,(,)又变得更快了

#!/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
不要在明智的系统上没有双引号的情况下尝试
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;

给出使用交换的进程的总数和百分比

smem -t -p


来源:

这里有一个版本,它的输出与@loolotux的脚本相同,但速度要快得多(但可读性较差)。 这个循环在我的机器上大约需要10秒,我的版本需要0.019秒,这对我很重要,因为我想把它变成一个cgi页面

join-t/-13-23\

自2015年添加了
SwapPss
()最终可以得到比例交换计数,这意味着如果一个进程交换了很多次,然后它分叉,那么两个分叉的进程将分别报告交换50%。如果其中一个分叉,每个进程将被计算为交换页面的33%。因此,如果将所有这些交换使用情况一起计算,则得到的是实际的交换使用情况,而不是值乘以进程
read FIELD PROGNAME < <(
    perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/status
)
echo $FIELD "$PROGNAME"
#!/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
smem -t -p
(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)
awk: cmd. line:1: fatal: cannot open file `15407/smaps' for reading (No such file or directory)
$ 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
$ 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"
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