Come scoprire quali processi utilizzano lo spazio di swap in Linux?


240

Sotto Linux, come faccio a sapere quale processo utilizza maggiormente lo spazio di swap?


30
La tua risposta accettata è sbagliata. Considera di cambiarlo nella risposta di lolotux, che in realtà è corretta.
jterrace,

@jterrace è corretto, non ho tanto spazio di scambio quanto la somma dei valori nella colonna SWAP in alto.
Akostadinov,

1
iotop è un comando molto utile che mostrerà statistiche in tempo reale sull'uso di io e swap per processo / thread
sunil

@jterrace, prendere in considerazione affermando cui accettato-risposta-of-the-day è sbagliato. Sei anni dopo, il resto di noi non ha idea se ci si riferisse alla risposta di David Holm (quella attualmente accettata a partire da oggi) o qualche altra risposta. (Bene, vedo che hai anche detto che la risposta di David Holm è sbagliata, come commento alla sua risposta ... quindi immagino che probabilmente intendevi la sua.)
Don Hatch,

Risposte:


106

Eseguire la parte superiore quindi premere OpEnter. Ora i processi dovrebbero essere ordinati in base al loro utilizzo di swap.

Ecco un aggiornamento poiché la mia risposta originale non fornisce una risposta esatta al problema, come sottolineato nei commenti. Dalle domande frequenti su htop :

Non è possibile ottenere la dimensione esatta dello spazio di swap utilizzato di un processo. Top falsifica queste informazioni creando SWAP = VIRT - RES, ma questa non è una buona metrica, perché anche altre cose come la memoria video conta su VIRT (ad esempio: top dice che il mio processo X sta usando 81M di swap, ma anche segnala che il mio sistema nel suo complesso utilizza solo 2 milioni di swap. Pertanto, non aggiungerò una colonna Swap simile a htop perché non conosco un modo affidabile per ottenere queste informazioni (in realtà, non penso che sia possibile ottenere un numero esatto, a causa delle pagine condivise).


137
Dai documenti, la colonna SWAP in alto sembra mostrare solo quanto swap sarebbe necessario se l'intero processo fosse scambiato, piuttosto che quanto del processo è attualmente scambiato. Da quello che posso dire dopo una breve ricerca, non c'è modo di determinare la quantità di ogni processo scambiata al momento. L'autore di htop si rifiuta di inserire una colonna del genere a causa di ciò (vedo le colonne CNSWAP e NSWAP, ma non sembrano fare nulla sulla mia macchina): htop.sourceforge.net/index.php?page=faq
yukondude,

6
@yukondude ha ragione, la colonna SWAP in alto è solo VIRT - RES e questa informazione è una specie di inutile in questo contesto. Non è previsto alcun compenso, ad esempio, per la memoria condivisa della RAM video mappata. Inoltre, il processo potrebbe non aver ancora fatto riferimento a tutta la memoria. In questo caso non è necessario che il sistema operativo legga il file binario completo dal disco in memoria, e quindi il valore di RES non include questa parte della memoria.
Bart

Voterei questo più se potessi. Questo mi sta risparmiando la pancetta!
atrain

Per fortuna, questo è quello che sono i commenti per @jterrace :) (anche se è vero che devi leggerli: S ... non sono sicuro di cosa si riferisca atrain, spero sia yukondude)
AJP,

11
Per quanto riguarda il commento non funziona più: sembra che le versioni più recenti di top non abbiano più 'O' impostato come chiave per la scelta dei campi di ordinamento. Quando si utilizza il? chiave puoi vedere il nome e la versione del programma attuale, procps-ng essendo l'ultima versione. Questo è un fork di Debian, Fedora e openSUSE: gitorious.org/procps . Se desideri comunque effettuare un ordinamento nella colonna SWAP: usa il tasto 'f' per visualizzare i campi, usa i tasti freccia per andare su SWAP e usa 's' per impostare l'ordinamento, quindi 'q'.
Pieter VN,

294

La migliore sceneggiatura che ho trovato è su questa pagina: http://northernmost.org/blog/find-out-what-is-using-your-swap/

Ecco una variante dello script e non è necessaria alcuna radice:

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


4
divertente però, ottengo Overall swap used: 260672 KB, mentre spettacoli gratuiti 738932come usato ...
Doncho Gunchev

23
Stesso output dieci volte più veloce: for file in /proc/*/status ; do awk '/Tgid|VmSwap|Name/{printf $2 " " $3}END{ print ""}' $file; done | grep kB | sort -k 3 -nper Debian / RH 6x +, Arch, Ubuntu (RH 5x ha VmSize) ( sorgente ). Come @dgunchev, offre uno swap totale molto meno di free. @Tensibai non funziona su Arch; il tuo awk potrebbe non avere qualcosa.
tuk0z,

1
Dai un'occhiata alla mia versione senza fork di questo script!
F. Hauri,

3
L'autore ha un post di follow-up su come farlo usando top: northernmost.org/blog/swap-usage-5-years-later
Jack Valmadre

53

Ecco un'altra variante dello script, ma intendeva fornire un output più leggibile (è necessario eseguirlo come root per ottenere risultati esatti):

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

2
Sceneggiatura molto bella. Fornisce le stesse informazioni di quella di lolotux, ma in un modo meglio leggibile.
Philipp Wendler,

Uscita eccellente. Grazie.
Brian Cline,

2
L'unica cosa che ho cambiato è stata usare argsinvece che commnel pscomando poiché ho molti processi con lo stesso nome ma argomenti diversi (un gruppo di processi Python Gunicorn). ps -p $PID -o args --no-headers
Vale a

1
La nota a grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'awk ' /VmSwap/ { print $2 }'
margine

12

Ho notato che questo thread è piuttosto vecchio, ma se ti capita di imbatterti in esso, come ho appena fatto, un'altra risposta è: usa smem.

Ecco un link che ti dice sia come installarlo che come usarlo:

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


Questo è buono Ecco la versione adattata di quell'articolo per mostrare i proc ordinati per utilizzo dello swap con PID aggiunto: $ per il file in / proc / * / status; do awk '/ ^ Pid | VmSwap | Nome / {printf $ 2 "" $ 3} END {print ""}' $ file; fatto | ordina -k 3 -n -r | meno
Stan Brajewski,

Dovresti glob / proc / [1-9] * / status per escludere un paio di voci speciali / proc e puoi combinare gli argomenti di ordinamento come -rnk3
dland

10

Non è del tutto chiaro se vuoi dire che vuoi trovare il processo che ha sostituito la maggior parte delle pagine o il processo che ha causato lo scambio della maggior parte delle pagine.

Per il primo è possibile eseguire tope ordinare tramite swap (premere 'Op'), per il secondo è possibile eseguire vmstate cercare voci diverse da zero per 'so'.


6

Il comando superiore contiene anche un campo per visualizzare il numero di errori di pagina per un processo. Il processo con massimo errore di pagina sarebbe il processo che sta scambiando di più. Per i demoni a esecuzione prolungata potrebbe essere che all'inizio si verifichino un numero elevato di errori di pagina e il numero non aumenterà in seguito. Quindi dobbiamo osservare se gli errori di pagina stanno aumentando.


6

Un'altra variante di script che evita il loop nella 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
  }'

L'utilizzo standard è script.shquello di ottenere l'utilizzo per programma con ordine casuale (fino a come awkmemorizza i suoi hash) o script.sh 1ordinare l'output per pid.

Spero di aver commentato abbastanza il codice per dire cosa fa.


1
Si noti che bashespande le directory in modo ordinato (lessicale, non numerico). L'ordine casuale dipende da come awkmemorizza le sue matrici (tabella hash) e da come le for p in pnamerecupera.
Stephane Chazelas,

@StephaneChazelas Beh, non è nemmeno lessicale, è un ordinamento di codice ASCII (come /proc/1/statusviene dopo /proc/1992/statuse che /ha un codice ASCII sopra il codice ASCII 9. Questo dà anche un aspetto e un "ordine casuale". Sono d'accordo con la tabella hash awk , Ho preso una scorciatoia qui. Sentiti libero di modificare la risposta per mantenere l'attribuzione nella cronologia delle modifiche.
Tensibai,

1
/proc/1/statusnon verrebbe dopo /proc/1992/statusnella locale C dove l'ordine si basa sul valore byte. Lo fa nel tuo locale (o nel mio en_GB.UTF-8su un sistema GNU), perché /viene ignorato nella prima istanza dell'algoritmo di fascicolazione (e sordina dopo 9). Confronta printf '/proc/%s/status\n' 1 1992 | LC_ALL=en_GB.UTF-8 sortcon printf '/proc/%s/status\n' 1 1992 | LC_ALL=C sort. In locali diversi da C, l'ordinamento generalmente non si basa sul valore byte.
Stephane Chazelas,

@StephaneChazelas Bel punto, non ho pensato al locale. Ancora una volta sentiti libero di modificare per aggiungere la precisione in modo che i crediti saranno tuoi (almeno nella modifica della cronologia).
Tensibai,

2
Fatto. Questa risposta è molto meglio di quella più votata qui. Merita più voti. Quella e altre risposte qui sono state discusse in Perché usare un loop di shell per elaborare il testo è considerato una cattiva pratica? che è ciò che mi ha portato qui.
Stephane Chazelas,

6

Altre due varianti:

Poiché topo htoppotrebbe non essere installato su piccoli sistemi, la navigazione /procrimane sempre possibile.

Anche su piccoli sistemi, troverai un shell...

UN variante! (Non solo bash)

Questo è esattamente lo stesso dello script lolotux , ma senza fork a grep, awko ps. Questo è molto più veloce!

E come è uno dei più poveri per quanto riguarda le prestazioni, è stato fatto un piccolo lavoro per garantire che questo script funzionasse bene , e alcuni altri. Quindi, ( grazie a Stéphane Chazelas ,) diventa di nuovo molto più veloce!

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

Non dimenticare di raddoppiare la citazione "$PROGNAME"! Vedi il commento di Stéphane Chazelas :

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

Non provare echo $PROGNAMEsenza una doppia citazione sul sistema sensibile ed essere pronto a uccidere la shell corrente prima!

E a versione

Dato che questo diventa uno script non così semplice , sta arrivando il momento di scrivere uno strumento dedicato usando un linguaggio più efficiente.

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

potrebbe essere eseguito con uno dei

-c  sort by command name
-p  sort by pid
-m  sort by swap values
by default, output is sorted by status's vmsize

Presuppone che i nomi dei processi non contengano spazio, tabulazione :, barra rovesciata, caratteri jolly o caratteri di controllo.
Stephane Chazelas,

@StephaneChazelas Grazie! Ho aggiunto [1-9]prima *per contare solo i percorsi numerati (no self, né thread-self)
F. Hauri il

1
La sintassi è nota, ma i nomi dei processi non lo sono. Almeno cita le tue variabili . (in ogni caso, la tua sceneggiatura è molto meno male di loloxux ').
Stephane Chazelas,

1
I nomi dei processi su Linux possono contenere qualsiasi valore di byte tranne 0 ma sono limitati a 15 byte di lunghezza. La Namevoce in /proc/*/statuscodifica alcuni di questi valori di byte. Prova ad esempio perl -ne 'BEGIN{$0="\n\t\\"} print if /^Name/' /proc/self/status. Perché è così breve, il danno che può essere fatto con cose del genere perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/statusè limitato quando ti dimentichi di citare le tue variabili.
Stephane Chazelas,

1
Questa (almeno la versione perl che ho appena provato) è enormemente più veloce delle altre risposte.
David Gardner,

5

Ho adattato una diversa sceneggiatura sul web a questo lungo 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 ; }

Che poi lancio in un cronjob e reindirizzo l'output a un file di registro. Le informazioni qui sono le stesse dell'accumulo delle Swap:voci nel file smaps, ma se vuoi essere sicuro, puoi usare:

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

L'output di questa versione è in due colonne: pid, importo di scambio. Nella versione precedente, trrimuove i componenti non numerici. In entrambi i casi, l'output viene ordinato numericamente per pid.


2
Questo è buono, ma il primo ordina per pid crescente (sort -n). L'utilizzo migliore è di averlo ordinato in base all'utilizzo dello swap in ordine decrescente (il più utilizzato prima dell'elenco). Per ottenerlo, cambia "ordina -n" in "ordina -n -k 3 -r"
Stan Brajewski,

3

Su MacOSX, esegui anche il comando top ma devi digitare "o", quindi "vsize" quindi INVIO.


2

Suppongo che potresti avere una buona idea eseguendo tope cercando processi attivi che usano molta memoria. Fare questo a livello di programmazione è più difficile --- basta guardare agli infiniti dibattiti sull'euristica killer di OOM Linux.

Scambio è una funzione di avere più memoria in attivo uso rispetto è installato, quindi è solitamente difficile colpa a un singolo processo. Se si tratta di un problema in corso, la soluzione migliore è installare più memoria o apportare altre modifiche sistemiche.



1

Non conosco alcuna risposta diretta su come trovare esattamente quale processo sta utilizzando lo spazio di scambio, tuttavia, questo collegamento può essere utile . Un altro buono è qui

Inoltre, usa un buon strumento come htop per vedere quali processi stanno usando molta memoria e quanta swap in generale viene utilizzata.


1

iotopè uno strumento molto utile. Fornisce statistiche in tempo reale di I / O e utilizzo degli swap per processo / thread. Per impostazione predefinita, mostra per thread ma è possibile fare iotop -Pper ottenere informazioni sul processo. Questo non è disponibile per impostazione predefinita. Potrebbe essere necessario installare tramite rpm / apt.


1

Ecco una versione che produce lo stesso script di @loolotux, ma è molto più veloce (anche se meno leggibile). Quel ciclo impiega circa 10 secondi sulla mia macchina, la mia versione impiega 0,019 s, il che conta per me perché volevo trasformarlo in una pagina 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

1

Dalla patch del kernel dell'anno 2015 che aggiunge SwapPss( https://lore.kernel.org/patchwork/patch/570506/ ) si può finalmente ottenere un conteggio di swap proporzionale, il che significa che se un processo ha scambiato molto e poi si biforca, entrambi i processi biforcati sarà segnalato per scambiare il 50% ciascuno. E se uno dei due viene eseguito il fork, ogni processo viene conteggiato al 33% delle pagine scambiate, quindi se si contano tutti quegli utilizzi di scambio, si ottiene un reale utilizzo dello scambio anziché il valore moltiplicato per il conteggio dei processi.

In breve:

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

La prima colonna è pid, la seconda colonna è l'utilizzo dello scambio in KiB e il resto della riga è l'esecuzione del comando. I conteggi identici di swap sono ordinati per pid.

Sopra può emettere linee come

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

il che significa semplicemente che il processo con pid 15407 si è concluso tra vederlo nell'elenco /proc/e leggere il smapsfile di processo . Se questo è importante per te, aggiungi semplicemente 2>/dev/nullfino alla fine. Tieni presente che potenzialmente perderai anche qualsiasi altra diagnostica possibile.

Nel caso di esempio nel mondo reale, questo cambia altri strumenti che riportano un utilizzo dello scambio di ~ 40 MB per ciascun figlio apache in esecuzione su un server in un utilizzo effettivo compreso tra 7-3630 KB realmente utilizzato per figlio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.