Como descobrir quais processos estão usando espaço de troca no Linux?

240

No Linux, como descubro qual processo está usando mais o espaço de troca?

Shameem
fonte
30
Sua resposta aceita está errada. Considere alterá-lo para a resposta do lolotux, que está realmente correta.
jterrace
@jterrace está correto, não tenho tanto espaço de troca quanto a soma dos valores na coluna SWAP na parte superior.
akostadinov 30/08/2012
1
iotop é um comando muito útil que irá mostrar estatísticas ao vivo de io e uso de troca por processo / thread
Sunil
@jterrace, considere declarar cuja resposta aceita do dia está errada. Seis anos depois, o resto de nós não tem idéia se você estava se referindo à resposta de David Holm (a atualmente aceita até hoje) ou alguma outra resposta. (Bem, eu vejo que você também disse que a resposta de David Holm é errado, como um comentário sobre a sua resposta ... então eu acho que você provavelmente quis dizer dele.)
Don escotilha

Respostas:

106

Corra para cima e pressione OpEnter. Agora os processos devem ser classificados pelo uso de troca.

Aqui está uma atualização, pois minha resposta original não fornece uma resposta exata para o problema, conforme apontado nos comentários. Na FAQ do htop :

Não é possível obter o tamanho exato do espaço de troca usado de um processo. O Top falsifica essas informações criando SWAP = VIRT - RES, mas essa não é uma boa métrica, porque outras coisas, como a memória de vídeo, também contam com o VIRT (por exemplo: top diz que meu processo X está usando 81M de swap, mas também relata que meu sistema como um todo está usando apenas 2M de swap.Portanto, não adicionarei uma coluna Swap semelhante ao htop porque não conheço uma maneira confiável de obter essas informações (na verdade, acho que não é possível obter um número exato, devido às páginas compartilhadas).

David Holm
fonte
137
A partir dos documentos, a coluna SWAP na parte superior parece apenas mostrar quanto de troca seria necessário se todo o processo fosse trocado, em vez de quanto do processo é realmente trocado no momento. Pelo que sei depois de uma breve pesquisa, não há como determinar quanto de cada processo é trocado no momento. O autor do htop se recusa a colocar essa coluna por causa disso (vejo as colunas CNSWAP e NSWAP, mas elas parecem não fazer nada na minha máquina): htop.sourceforge.net/index.php?page=faq
Yukondude 11/11/2009
6
@yukondude está certo, a coluna SWAP no topo é apenas VIRT - RES e essa informação é um tipo de inútil nesse contexto. Não há compensação para, por exemplo, memória compartilhada da RAM de vídeo mapeada. Além disso, nem toda a memória pode ter sido referenciada pelo processo ainda. Nesse caso, não é necessário que o sistema operacional leia o binário completo do disco na memória e, portanto, o valor de RES não inclui essa parte da memória.
Bart
Eu votaria mais nisso se pudesse. Isso está salvando meu bacon!
atrain
Felizmente isso é o que os comentários são para @jterrace :) (embora se admita que você tem que lê-los: S ... não sei o que atrain está se referindo, espero que da yukondude)
AJP
11
Quanto ao comentário não funcionar mais: parece que as versões mais recentes do top não têm mais 'O' definido como a chave para escolher os campos de classificação. Ao usar o? Você pode ver o nome e a versão reais do programa, sendo procps-ng a versão mais recente. Este é um fork do Debian, Fedora e openSUSE: gitorious.org/procps . Se você ainda deseja fazer uma classificação na coluna SWAP: Use a tecla 'f' para ver os campos, use as teclas de seta para ir para SWAP e use 's' para definir a classificação e, em seguida, 'q'.
precisa saber é o seguinte
294

O melhor script que encontrei está nesta página: http://nouthernmost.org/blog/find-out-what-is-using-your-swap/

Aqui está uma variante do script e nenhuma raiz é necessária:

#!/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"
lolotux
fonte
Aqui está a cópia, caso o link morra: gitorious.org/dolanormisc/scripts/blobs/master/getswapused
TautrimasPajarskas
4
engraçado, porém, eu recebo Overall swap used: 260672 KB, enquanto shows gratuitos 738932como usado ...
Doncho Gunchev
23
A mesma saída dez vezes mais rápida: for file in /proc/*/status ; do awk '/Tgid|VmSwap|Name/{printf $2 " " $3}END{ print ""}' $file; done | grep kB | sort -k 3 -npara Debian / RH 6x +, Arch, Ubuntu (RH 5x possui VmSize) ( fonte ). Como @dgunchev, ele oferece muito menos troca total do que free. @Tensibai não funciona no Arch; seu awk pode faltar alguma coisa.
tuk0z
1
Por favor, dê uma olhada na minha versão sem garfo deste script!
11556 F. Hauri
3
O autor tem um post de acompanhamento sobre como fazê-lo usando top: northernmost.org/blog/swap-usage-5-years-later
Jack Valmadre
53

Aqui está outra variante do script, mas destinada a fornecer uma saída mais legível (você precisa executá-lo como root para obter resultados exatos):

#!/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}/";
j3nda
fonte
2
Script muito bom. Ele fornece as mesmas informações que as do lolotux, mas de uma maneira mais legível.
Philipp Wendler
Excelente saída. Obrigado.
quer
2
A única coisa que mudei foi usar em argsvez de commno pscomando, pois tenho muitos processos com o mesmo nome, mas com argumentos diferentes (vários processos python gunicorn). ps -p $PID -o args --no-headers
Ou
1
Nota lateral o grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'poderia ser simplificado comoawk ' /VmSwap/ { print $2 }'
Tensibai
12

Notei que esse tópico é bastante antigo, mas se você o encontrar, como eu acabei de fazer, outra resposta é: use smem.

Aqui está um link que informa sobre como instalá-lo e como usá-lo:

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

Tom
fonte
Este é bom. Aqui está a versão adaptada desse artigo para mostrar os procs classificados pelo uso de swap com o PID adicionado: $ para arquivo em / proc / * / status; faça awk '/ ^ Pid | VmSwap | Name / {printf $ 2 "" $ 3} END {print ""}' $ file; feito | ordenar -k 3 -n -r | menos
Stan Brajewski
Você deve glob / proc / [1-9] * / status para excluir algumas entradas especiais / proc e pode combinar a classificação args como -rnk3
dland
10

Não está totalmente claro se você quer encontrar o processo com a maioria das páginas trocadas ou o processo que causou a troca de muitas páginas.

No primeiro, você pode executar tope ordenar por troca (pressione 'Op'); no último, você pode executar vmstate procurar entradas diferentes de zero para 'so'.

Ronny Vindenes
fonte
6

O comando top também contém um campo para exibir o número de falhas de página para um processo. O processo com falhas máximas de página seria o processo que mais trocaria. Para daemons de longa execução, pode ser que eles apresentem um grande número de falhas de página no início e o número não aumente posteriormente. Portanto, precisamos observar se as falhas da página estão aumentando.

Amol Kulkarni
fonte
6

Outra variante de script que evita o loop no 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
  }'

O uso padrão é script.shobter o uso por programa em ordem aleatória (até como awkarmazena seus hashes) ou script.sh 1classificar a saída por pid.

Espero ter comentado o código o suficiente para dizer o que ele faz.

Tensibai
fonte
1
Observe que bashexpande os diretórios de maneira ordenada (lexical, não numérica). A ordem aleatória se resume a como awkas matrizes são armazenadas (tabela de hash) e como as for p in pnamerecupera.
Stephane Chazelas
@StephaneChazelas Bem, isso não é nem lexicalmente, é um tipo de código ASCII (como /proc/1/statusvem depois /proc/1992/statuse que /tem um código ASCII acima do código ASCII 9. Isso também dá uma aparência e uma "ordem aleatória". Concordo com a tabela de hash awk , tomei um atalho aqui Sinta-se livre para editar a resposta para manter a atribuição no histórico de edições..
Tensibai
1
/proc/1/statusnão viria depois /proc/1992/statusna localidade C, em que o pedido é baseado no valor do byte. Isso ocorre no seu código de idioma (ou no meu en_GB.UTF-8em um sistema GNU), porque /é ignorado em primeira instância no algoritmo de agrupamento (e sdepois 9). Compare printf '/proc/%s/status\n' 1 1992 | LC_ALL=en_GB.UTF-8 sortcom printf '/proc/%s/status\n' 1 1992 | LC_ALL=C sort. Em locais diferentes C, a ordem de classificação geralmente não se baseia no valor do byte.
Stephane Chazelas
@StephaneChazelas Bom ponto, não pensei no local. Mais uma vez, sinta-se à vontade para editar e adicionar a precisão para que os créditos sejam seus (pelo menos na edição do histórico).
Tensibai
2
Feito. Esta resposta é muito melhor do que a mais votada aqui. Merece mais votos positivos. Essa e outras respostas aqui foram discutidas em Por que o uso de um loop de shell para processar o texto é considerado uma má prática? que foi o que me trouxe aqui.
Stephane Chazelas
6

Mais duas variantes:

Como topou htopnão pôde ser instalado em sistemas pequenos, a navegação /procsempre é possível.

Mesmo em pequenos sistemas, você encontrará um shell...

UMA variante! (Não apenas bash)

É exatamente o mesmo que o script lolotux , mas sem nenhum garfo para grep, awkou ps. Isso é muito mais rápido!

E como é um dos mais pobres em relação ao desempenho, foi feito um pouco de trabalho para garantir que esse script funcione bem sob , e alguns outros. Então, ( graças a Stéphane Chazelas ,) tornou-se muito mais rápido novamente!

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

Não se esqueça de citar duas vezes "$PROGNAME"! Veja o comentário de Stéphane Chazelas :

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

Não tente echo $PROGNAMEsem aspas duplas no sistema sensível e esteja pronto para matar o shell atual antes!

E um versão

Como isso se tornou um script não tão simples , está chegando a hora de escrever uma ferramenta dedicada usando uma linguagem mais eficiente.

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

poderia correr com um dos

-c  sort by command name
-p  sort by pid
-m  sort by swap values
by default, output is sorted by status's vmsize
F. Hauri
fonte
Ele assume que os nomes dos processos não contêm caracteres de espaço, tabulação :, barra invertida, curinga ou controle.
Stephane Chazelas
@StephaneChazelas Thanks! Eu adicionei [1-9]antes *para contar apenas os caminhos numerados (não self, nem thread-self) #
F. Hauri
1
A sintaxe é conhecida, mas os nomes dos processos não. Cite pelo menos suas variáveis . (em qualquer caso, seu script é muito menos ruim que o loloxux ').
Stephane Chazelas 8/08/16
1
Os nomes de processos no Linux podem conter qualquer valor de byte, mas 0, mas estão limitados a 15 bytes de comprimento. A Nameentrada /proc/*/statuscodifica alguns desses valores de bytes. Tente por exemplo perl -ne 'BEGIN{$0="\n\t\\"} print if /^Name/' /proc/self/status. Por ser tão curto, o dano que pode ser causado com coisas do tipo perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/statusé limitado quando você esquece de citar suas variáveis.
Stephane Chazelas 8/08/16
1
Esta (pelo menos a versão perl que acabei de experimentar) é muito mais rápida que as outras respostas.
David Gardner
5

Eu adaptei um script diferente na web para esse longo artigo:

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

Que eu joguei em um cronjob e redirecionei a saída para um arquivo de log. As informações aqui são as mesmas de acumular as Swap:entradas no arquivo smaps, mas se você quiser ter certeza, pode usar:

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

A saída desta versão está em duas colunas: pid, quantidade de swap. Na versão acima, trretira os componentes não numéricos. Nos dois casos, a saída é classificada numericamente por pid.

Otheus
fonte
2
Isso é bom, mas o primeiro classifica por pid ascendente (sort -n). O melhor uso é ordená-lo por uso de swap em ordem decrescente (o mais usado na frente da lista). Para obtê-lo mudar "tipo -n" para "sort -n k 3 -r"
Stan Brajewski
3

No MacOSX, você executa o comando top também, mas precisa digitar "o" e depois "vsize" e, em seguida, ENTER.

Alexis
fonte
2

Suponho que você poderia adivinhar executando tope procurando processos ativos usando muita memória. Fazer isso programaticamente é mais difícil - basta olhar para os intermináveis ​​debates sobre as heurísticas do killer do Linux OOM.

A troca é uma função de ter mais memória em uso ativo do que a instalada, por isso é geralmente difícil culpá-la em um único processo. Se houver um problema contínuo, a melhor solução é instalar mais memória ou fazer outras alterações sistêmicas.

dmckee --- gatinho ex-moderador
fonte
1

Não conheço nenhuma resposta direta sobre como encontrar exatamente qual processo está usando o espaço de troca, no entanto, esse link pode ser útil . Outra boa é aqui

Além disso, use uma boa ferramenta como a htop para ver quais processos estão usando muita memória e quanto swap global está sendo usado.

Jean Azzopardi
fonte
1

iotopé uma ferramenta muito útil. Ele fornece estatísticas ao vivo de E / S e troca de uso por processo / encadeamento. Por padrão, ele é exibido por thread, mas você pode fazer isso iotop -Ppara obter informações por processo. Isso não está disponível por padrão. Você pode ter que instalar via rpm / apt.

tomar sol
fonte
1

Aqui está uma versão que gera o mesmo que o script do @loolotux, mas é muito mais rápida (embora menos legível). Esse loop leva cerca de 10 segundos na minha máquina, minha versão leva 0,019 s, o que era importante para mim porque eu queria transformá-lo em uma página 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
Dmitry z
fonte
1

Desde o ano de 2015, o patch do kernel que adiciona SwapPss( https://lore.kernel.org/patchwork/patch/570506/ ) pode-se finalmente obter uma contagem proporcional de trocas, o que significa que se um processo tiver trocado muito e forjado, os dois processos bifurcados será relatado para trocar 50% cada. E, se um dos dois for bifurcado, cada processo contará 33% das páginas trocadas; portanto, se você contar todos esses usos de troca juntos, obterá um uso real da troca, em vez do valor multiplicado pela contagem do processo.

Em resumo:

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

A primeira coluna é pid, a segunda coluna é o uso de swap no KiB e o restante da linha é o comando sendo executado. Contagens de troca idênticas são classificadas por pid.

Acima pode emitir linhas como

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

o que significa simplesmente que o processo com o pid 15407 terminou entre vê-lo na lista /proc/e ler o smapsarquivo do processo . Se isso importa para você, basta adicionar 2>/dev/nullaté o fim. Observe que você também perderá outros diagnósticos possíveis.

No caso de exemplo do mundo real, isso altera outras ferramentas que relatam ~ 40 MB de uso de troca para cada filho apache em execução em um servidor para uso real entre 7-3630 KB realmente usado por filho.

Mikko Rantalainen
fonte