¿Cómo averiguar qué procesos están utilizando el espacio de intercambio en Linux?

240

En Linux, ¿cómo puedo saber qué proceso está usando más el espacio de intercambio?

Shameem
fuente
30
Su respuesta aceptada es incorrecta. Considere cambiarlo a la respuesta de lolotux, que en realidad es correcta.
jterrace
@jterrace es correcto, no tengo tanto espacio de intercambio como la suma de los valores en la columna SWAP en la parte superior.
akostadinov
1
iotop es un comando muy útil que mostrará estadísticas en vivo de io y el uso de intercambio por proceso / hilo
sunil
@jterrace, considere que indica cuya aceptado-respuesta-de-la-día es erróneo. Seis años después, el resto de nosotros no tenemos idea de si se estaba refiriendo a la respuesta de David Holm (la actualmente aceptada hasta el día de hoy) o alguna otra respuesta. (Bueno, veo que también ha dicho la respuesta de David Holm es incorrecto, como un comentario en su respuesta ... así que supongo que probablemente se refería a su.)
Don Hatch

Respuestas:

106

Corre arriba y luego presiona OpEnter. Ahora los procesos deben ordenarse por su uso de intercambio.

Aquí hay una actualización ya que mi respuesta original no proporciona una respuesta exacta al problema como se señala en los comentarios. De las preguntas frecuentes de htop :

No es posible obtener el tamaño exacto del espacio de intercambio utilizado de un proceso. Top falsifica esta información al hacer SWAP = VIRT - RES, pero esa no es una buena métrica, porque otras cosas como la memoria de video también cuenta en VIRT (por ejemplo: top dice que mi proceso X está utilizando 81M de intercambio, pero también informa que mi sistema en su conjunto está usando solo 2M de intercambio. Por lo tanto, no agregaré una columna de intercambio similar a htop porque no conozco una forma confiable de obtener esta información (en realidad, no creo que sea posible obtener un número exacto, debido a las páginas compartidas).

David Holm
fuente
137
De los documentos, la columna SWAP en la parte superior parece mostrar cuánto intercambio sería necesario si se intercambiara todo el proceso, en lugar de cuánto se intercambia actualmente el proceso. Por lo que puedo decir después de una breve búsqueda, no hay forma de determinar cuánto de cada proceso se intercambia en este momento. El autor de htop se niega a poner una columna de este tipo debido a esto (veo columnas CNSWAP y NSWAP, pero no parecen hacer nada en mi máquina): htop.sourceforge.net/index.php?page=faq
yukondude
66
@yukondude tiene razón, la columna SWAP en la parte superior es solo VIRT - RES y esta información es un poco inútil en este contexto. No hay compensación para, por ejemplo, la memoria compartida de la RAM de video asignada. Además, es posible que el proceso no haya hecho referencia a toda la memoria. En este caso, no es necesario que el sistema operativo lea el binario completo del disco en la memoria y, por lo tanto, el valor de RES no incluye esta parte de la memoria.
Bart
Votaría esto más si pudiera. ¡Esto está salvando mi tocino!
atrain
Afortunadamente, eso es lo que los comentarios son para @jterrace :) (aunque es cierto que tienes que leerlos: S ... no estoy seguro de a qué se refiere atrain, espero que sea yukondude)
AJP
11
Con respecto al comentario que ya no funciona: parece que las versiones más recientes de top ya no tienen 'O' establecida como la clave para elegir los campos de clasificación. Cuando se usa el? Puede ver el nombre y la versión del programa real, siendo procps-ng la última versión. Este es un fork de Debian, Fedora y openSUSE: gitorious.org/procps . Si aún desea hacer una clasificación en la columna SWAP: use la tecla 'f' para ver los campos, use las teclas de flecha para ir a SWAP y use 's' para establecer la clasificación, luego 'q'.
Pieter VN
294

El mejor script que encontré está en esta página: http://northernmost.org/blog/find-out-what-is-using-your-swap/

Aquí hay una variante del script y no se necesita 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"
lolotux
fuente
Aquí está la copia, en caso de que el enlace muera: gitorious.org/dolanormisc/scripts/blobs/master/getswapused
TautrimasPajarskas
44
sin embargo, me Overall swap used: 260672 KB738932
parece
23
Misma salida diez veces más rápido: 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 tiene VmSize) ( fuente ). Al igual que @dgunchev, da mucho menos intercambio total que free. @Tensibai no funciona en Arch; tu awk puede carecer de algo.
tuk0z
1
¡Por favor, eche un vistazo a mi versión sin horquilla de este script!
F. Hauri
3
El autor tiene una publicación de seguimiento sobre cómo hacerlo usando top: northernmost.org/blog/swap-usage-5-years-later
Jack Valmadre
53

Aquí hay otra variante de la secuencia de comandos, pero destinada a proporcionar una salida más legible (debe ejecutar esto como raíz para obtener resultados exactos):

#!/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
fuente
2
Muy buen guión. Da la misma información que la de lolotux, pero de una mejor manera legible.
Philipp Wendler el
Excelente salida. Gracias.
Brian Cline
2
Lo único que he cambiado estaba usando argsen lugar de commen el pscomando ya que tengo una gran cantidad de procesos con el mismo nombre pero diferentes argumentos (un manojo de procesos pitón gunicorn). Es decir:ps -p $PID -o args --no-headers
mgalgs
1
Nota al grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'awk ' /VmSwap/ { print $2 }'
margen
12

Me di cuenta de que este hilo es bastante antiguo, pero si te topas con él, como acabo de hacer, otra respuesta es: usa smem.

Aquí hay un enlace que le indica cómo instalarlo y cómo usarlo:

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

Tom
fuente
Este es bueno. Aquí está la versión adaptada de ese artículo para mostrar procs ordenados por uso de intercambio con PID agregado: $ para el archivo en / proc / * / status; do awk '/ ^ Pid | VmSwap | Nombre / {printf $ 2 "" $ 3} END {print ""}' $ file; hecho | ordenar -k 3 -n -r | menos
Stan Brajewski
Debería glob / proc / [1-9] * / status para excluir un par de entradas especiales / proc, y puede combinar los argumentos de ordenación como -rnk3
dland
10

No está del todo claro si quiere decir que desea encontrar el proceso que ha intercambiado la mayoría de las páginas o el proceso que ha provocado el intercambio de la mayoría de las páginas.

Para el primero, puede ejecutar topy ordenar por intercambio (presione 'Op'), para el último puede ejecutar vmstaty buscar entradas que no sean cero para 'so'.

Ronny Vindenes
fuente
6

El comando superior también contiene un campo para mostrar el número de fallas de página para un proceso. El proceso con errores máximos de página sería el proceso que más se intercambia. Para los demonios de larga ejecución, es posible que incurran en un gran número de fallas de página al principio y que el número no aumente más adelante. Por lo tanto, debemos observar si las fallas de la página están aumentando.

Amol Kulkarni
fuente
6

Otra variante de script que evita el bucle en 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
  }'

El uso estándar es script.shobtener el uso por programa con orden aleatorio (hasta cómo awkalmacena sus hashes) u script.sh 1ordenar la salida por pid.

Espero haber comentado el código lo suficiente como para decir lo que hace.

Tensibai
fuente
1
Tenga en cuenta que bashexpande los directorios de forma ordenada (léxico, no numérico). El orden aleatorio depende de cómo awkalmacena sus matrices (tabla hash) y cómo las for p in pnamerecupera.
Stephane Chazelas
@StephaneChazelas Bueno, eso ni siquiera es léxico, es un tipo de código ASCII (como /proc/1/statusviene después /proc/1992/statusy que /tiene un código ASCII por encima del código ASCII 9. Esto le da un aspecto de "orden aleatorio" y también estoy de acuerdo. Estoy de acuerdo con la tabla de hash awk , Tomé un atajo aquí. Siéntase libre de editar la respuesta para mantener la atribución en el historial de edición.
Tensibai
1
/proc/1/statusno vendría después /proc/1992/statusen la configuración regional C donde el orden se basa en el valor del byte. Lo hace en su configuración regional (o en mi en_GB.UTF-8en un sistema GNU), porque /se ignora en primera instancia en el algoritmo de clasificación (y se sordena después 9). Comparar 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. En entornos locales que no sean C, el orden de clasificación generalmente no se basa en el valor de byte.
Stephane Chazelas
@StephaneChazelas Buen punto, no pensé en la configuración regional. Nuevamente, siéntase libre de editar para agregar la precisión para que los créditos sean suyos (al menos en la edición de historial).
Tensibai
2
Hecho. Esta respuesta es mucho mejor que la más votada aquí. Se merece más votos a favor. Esa y otras respuestas aquí se discutieron en ¿Por qué usar un bucle de shell para procesar texto se considera una mala práctica? que es lo que me trajo aquí
Stephane Chazelas
6

Sin embargo, dos variantes más:

Debido a que topo htopno se puede instalar en sistemas pequeños, la navegación /procsiempre es posible.

Incluso en sistemas pequeños, encontrará shell...

UNA ¡variante! (No solo bash)

Esto es exactamente lo mismo que el script lolotux , pero sin ningún tenedor para grep, awko ps. ¡Esto es mucho más rápido!

Y como es uno de los más pobres con respecto al rendimiento, se realizó un pequeño trabajo para garantizar que este script se ejecute bien bajo , y alguna otra Entonces, ( gracias a Stéphane Chazelas ), ¡vuelve a ser mucho más rápido!

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

¡No te olvides de comillas dobles "$PROGNAME"! Ver el comentario de Stéphane Chazelas :

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

¡No lo intentes echo $PROGNAMEsin comillas dobles en un sistema sensible y prepárate para matar el shell actual antes!

Y un versión

A medida que esto se convierte en un guión no tan simple , llega el momento de escribir una herramienta dedicada mediante el uso de un lenguaje más 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;

podría correr con uno de

-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
fuente
Se supone que los nombres de los procesos no contienen espacios, tabuladores :, barras invertidas, comodines ni caracteres de control.
Stephane Chazelas
@StephaneChazelas ¡Gracias! He agregado [1-9]antes *para contar solo los caminos numerados (no self, ni thread-self)
F. Hauri
1
La sintaxis es conocida, pero los nombres de los procesos no. Al menos cita tus variables . (en cualquier caso, su script es mucho menos malo que loloxux ').
Stephane Chazelas
1
Los nombres de proceso en Linux pueden contener cualquier valor de byte pero 0 pero están limitados a 15 bytes de longitud. La Nameentrada en /proc/*/statuscodifica algunos de esos valores de bytes. Prueba por ejemplo perl -ne 'BEGIN{$0="\n\t\\"} print if /^Name/' /proc/self/status. Debido a que es tan corto, el daño que se puede hacer con cosas como perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/statuses limitado cuando olvida citar sus variables.
Stephane Chazelas
1
Esto (al menos la versión perl que acabo de probar) es enormemente más rápido que las otras respuestas.
David Gardner
5

Adapte un guión diferente en la web a esta larga línea:

 { 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 luego arrojo a un cronjob y redirijo la salida a un archivo de registro. La información aquí es lo mismo que acumular las Swap:entradas en el archivo smaps, pero si quieres estar seguro, puedes 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; }

El resultado de esta versión está en dos columnas: pid, cantidad de intercambio. En la versión anterior, las trtiras de los componentes no numéricos. En ambos casos, la salida se ordena numéricamente por pid.

Oteo
fuente
2
Esto es bueno, pero el primero se ordena pidiendo ascendente (sort -n). El mejor uso es ordenarlo por uso de intercambio en orden descendente (el que más se usa al frente de la lista). Para obtenerlo, cambie "sort -n" a "sort -n -k 3 -r"
Stan Brajewski
3

En MacOSX, ejecuta el comando superior también, pero necesita escribir "o", luego "vsize" y luego ENTER.

Alexis
fuente
2

Supongo que podrías adivinar si ejecutas topy buscas procesos activos con mucha memoria. Hacer esto programáticamente es más difícil, solo mira los interminables debates sobre la heurística asesina OOM de Linux.

El intercambio es una función de tener más memoria en uso activo de lo que está instalado, por lo que generalmente es difícil culparlo de un solo proceso. Si se trata de un problema continuo, la mejor solución es instalar más memoria o realizar otros cambios sistémicos.

dmckee --- gatito ex moderador
fuente
1

No conozco ninguna respuesta directa sobre cómo encontrar exactamente qué proceso está utilizando el espacio de intercambio, sin embargo, este enlace puede ser útil . Otra buena está por aquí

Además, use una buena herramienta como htop para ver qué procesos están usando mucha memoria y cuánto intercambio en general se está utilizando.

Jean Azzopardi
fuente
1

iotopEs una herramienta muy útil. Ofrece estadísticas en vivo de E / S y uso de intercambio por proceso / subproceso. De manera predeterminada, se muestra por hilo, pero puede hacerlo iotop -Ppara obtener información por proceso. Esto no está disponible por defecto. Puede que tenga que instalar a través de rpm / apt.

sunil
fuente
1

Aquí hay una versión que genera lo mismo que el script de @loolotux, pero es mucho más rápido (aunque menos legible). Ese ciclo toma alrededor de 10 segundos en mi máquina, mi versión toma 0.019 s, lo que me importó porque quería convertirlo en una 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
fuente
1

Desde el parche del kernel del año 2015 que agrega SwapPss( https://lore.kernel.org/patchwork/patch/570506/ ) finalmente se puede obtener un conteo de intercambio proporcional, lo que significa que si un proceso ha cambiado mucho y luego se bifurca, ambos procesos se bifurcan se informará que intercambiará el 50% cada uno. Y si cualquiera de las dos se bifurca, cada proceso cuenta el 33% de las páginas intercambiadas, por lo que si cuenta todos esos usos de intercambio juntos, obtendrá un uso de intercambio real en lugar del valor multiplicado por el recuento de procesos.

En 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 primera columna es pid, la segunda columna es el uso de intercambio en KiB y el resto de la línea se ejecuta el comando. Los recuentos de intercambio idénticos se ordenan por pid.

Arriba puede emitir líneas como

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

lo que simplemente significa que el proceso con pid 15407 terminó entre verlo en la lista /proc/y leer el smapsarchivo de proceso . Si eso te importa, simplemente agrégalo 2>/dev/nullal final. Tenga en cuenta que potencialmente también perderá cualquier otro diagnóstico posible.

En el caso de ejemplo del mundo real, esto cambia otras herramientas que informan ~ 40 MB de uso de intercambio para cada niño apache que se ejecuta en un servidor al uso real de entre 7-3630 KB realmente usado por niño.

Mikko Rantalainen
fuente