Как узнать, какие процессы используют пространство подкачки в Linux?

240

В Linux, как мне узнать, какой процесс больше использует пространство подкачки?

Шамим
источник
30
Ваш принятый ответ неверен. Подумайте об изменении его на ответ lolotux, что на самом деле правильно.
jterrace
@jterrace правильно, у меня не так много пространства подкачки, как сумма значений в столбце SWAP вверху.
Акостадинов
1
iotop - очень полезная команда, которая будет показывать в реальном времени статистику использования io и подкачки для процесса / потока
sunil
@jterrace, рассмотрите вопрос о том, чей принятый ответ дня неправильный. Шесть лет спустя остальные из нас не знают, имели ли вы в виду ответ Дэвида Холма (принятый на сегодняшний день) или какой-то другой ответ. (Ну, я вижу, вы также сказали, что ответ Дэвида Холма неправильный, как комментарий к его ответу ... так что, я думаю, вы, вероятно, имели в виду его.)
Дон Хэтч

Ответы:

106

Запустите сверху, затем нажмите OpEnter. Теперь процессы должны быть отсортированы по их использованию подкачки.

Вот обновление, так как мой оригинальный ответ не дает точного ответа на проблему, как указано в комментариях. Из htop FAQ :

Невозможно получить точный размер используемого пространства подкачки процесса. Top подделывает эту информацию, делая SWAP = VIRT - RES, но это не очень хорошая метрика, потому что другие вещи, такие как видеопамять, тоже учитываются в VIRT (например: top говорит, что мой процесс X использует 81M подкачки, но также сообщает, что моя система в целом использует только 2M подкачки. Поэтому я не буду добавлять аналогичный столбец подкачки в htop, потому что я не знаю надежного способа получить эту информацию (на самом деле, я не думаю, что это возможно получить точное число, из-за общих страниц).

Дэвид Холм
источник
137
Судя по документам, столбец SWAP в верхней части просто показывает, какой объем обмена был бы необходим, если бы весь процесс был заменен, а не то, сколько процесса фактически было заменено в настоящее время. Из того, что я могу сказать после короткого поиска, нет никакого способа определить, сколько из каждого процесса выгружено в данный момент. Из-за этого автор htop отказывается вставлять такой столбец (я вижу столбцы CNSWAP и NSWAP, но на моей машине они ничего не делают): htop.sourceforge.net/index.php?page=faq
yukondude
6
@yukondude прав, столбец SWAP вверху - просто VIRT - RES, и эта информация в этом контексте является бесполезной. Нет компенсации, например, для разделяемой памяти подключенного видеопамяти RAM. Также процесс может ссылаться не на всю память. В этом случае ОС не обязательно считывать весь двоичный файл с диска в память, и, таким образом, значение RES не включает эту часть памяти.
Барт
Я бы сказал больше, если бы мог. Это спасает мой бекон!
atrain
К счастью , это то , что комментарии являются для @jterrace :) (хотя по общему признанию , вы должны прочитать их: S ... не уверен , что atrain имеет в виду, я надеюсь , что это yukondude)
AJP
11
Относительно комментария, больше не работающего: кажется, что более поздние версии top больше не имеют «O» в качестве ключа для выбора полей сортировки. При использовании? ключом вы можете увидеть реальное название программы и версию, procps-ng является последней версией. Это форк от Debian, Fedora и openSUSE: gitorious.org/procps . Если вы все еще хотите выполнить сортировку по столбцу SWAP: используйте клавишу «f» для просмотра полей, используйте клавиши со стрелками для перехода к SWAP и используйте «s» для установки сортировки, затем «q».
Питер В.Н.
294

Лучший сценарий, который я нашел, находится на этой странице: http://northernmost.org/blog/find-out-what-is-using-your-swap/

Вот один из вариантов скрипта и без рута:

#!/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
источник
Вот копия, в случае, если ссылка умирает: gitorious.org/dolanormisc/scripts/blobs/master/getswapused
TautrimasPajarskas
4
Смешно, хотя, я получаю Overall swap used: 260672 KB, пока бесплатные шоу, 738932как используется ...
Дончо Ганчев
23
Тот же вывод в десять раз быстрее: for file in /proc/*/status ; do awk '/Tgid|VmSwap|Name/{printf $2 " " $3}END{ print ""}' $file; done | grep kB | sort -k 3 -nдля Debian / RH 6x +, Arch, Ubuntu (RH 5x имеет VmSize) ( источник ). Как и @dgunchev, он дает гораздо меньше общего свопа, чем free. @Tensibai не работает на Arch; в вашем awk может чего-то не хватать
tuk0z
1
Пожалуйста, посмотрите мою версию без скрипта!
Ф. Хаури
3
Автор имеет последующий пост о том , как сделать это с помощью top: northernmost.org/blog/swap-usage-5-years-later
Джек Valmadre
53

Вот еще один вариант скрипта, но он предназначен для получения более читабельного вывода (вам нужно запустить его как root, чтобы получить точные результаты):

#!/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
источник
2
Очень хороший сценарий. Он дает ту же информацию, что и лолотукс, но в более удобочитаемом виде.
Филипп Вендлер
Отличный выход. Спасибо.
Брайан Клайн
2
Единственное , что я изменил использовал argsвместо commв psкоманде , так как у меня есть много процессов , с тем же именем , но с разными аргументами (связка питон gunicorn процессов). ps -p $PID -o args --no-headers
То
1
Заметьте, что это grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'можно упростить какawk ' /VmSwap/ { print $2 }'
Tensibai
12

Я заметил, что эта ветка довольно старая, но если вы случайно наткнулись на нее, как я только что сделал, другой ответ: используйте smem.

Вот ссылка, которая расскажет вам, как установить его и как его использовать:

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

Том
источник
Это хорошо. Вот адаптированная версия из этой статьи, чтобы показать проки, отсортированные по использованию подкачки с добавленным PID: $ для файла в / proc / * / status; do awk '/ ^ Pid | VmSwap | Name / {printf $ 2 "" $ 3} END {print ""}' $ file; сделано | сортировка -k 3 -n -r | меньше
Стэн Браевски
Чтобы исключить пару специальных записей / proc, вы должны использовать glob / proc / [1-9] * / status, и вы можете комбинировать аргументы сортировки как -rnk3
dland
10

Не совсем понятно, хотите ли вы найти процесс, у которого было выгружено большинство страниц, или процесс, который вызвал замену большинства страниц.

Для первого вы можете запустить topи сделать заказ путем свопинга (нажмите «Op»), для последнего вы можете запустить vmstatи искать ненулевые записи для «так».

Ронни Винденес
источник
6

Команда top также содержит поле для отображения количества сбоев страниц для процесса. Процесс с максимальным количеством сбоев страниц будет процессом, который обменивается больше всего. Для длительно работающих демонов может случиться так, что они вначале сталкиваются с большим количеством сбоев страниц, и в дальнейшем это число не увеличивается. Таким образом, мы должны наблюдать, увеличивается ли количество ошибок на странице.

Амол Кулькарни
источник
6

Еще один вариант сценария, позволяющий избежать цикла в оболочке:

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

Стандартное использование состоит в том, script.shчтобы получить использование для каждой программы в случайном порядке (вплоть до того, как awkхранит ее хеши) или script.sh 1отсортировать вывод по pid.

Надеюсь, я прокомментировал код достаточно, чтобы рассказать, что он делает.

Tensibai
источник
1
Обратите внимание, что bashкаталоги расширяются отсортированным способом (лексическим, а не числовым). Случайный порядок сводится к тому, как awkхранить свои массивы (хеш-таблицу) и как for p in pnameих извлекать.
Стефан Шазелас
@StephaneChazelas Ну, это даже не лексика, это сортировка кода ascii (как /proc/1/statusследует из того, /proc/1992/statusчто /код ascii выше кода ascii 9. Это также дает внешний вид и случайный порядок). Я согласен с хеш-таблицей awk Я взял ярлык здесь. Не стесняйтесь редактировать ответ, чтобы сохранить атрибуцию в истории редактирования.
Тенсибай
1
/proc/1/statusне будет следовать /proc/1992/statusв локали C, где порядок основан на значении байта. Это происходит в вашей локали (или в моей en_GB.UTF-8системе GNU), потому /что в алгоритме сортировки в первом случае игнорируется (и sсортируется после 9). Сравните printf '/proc/%s/status\n' 1 1992 | LC_ALL=en_GB.UTF-8 sortс printf '/proc/%s/status\n' 1 1992 | LC_ALL=C sort. В других локалях Cпорядок сортировки обычно не основан на значении байта.
Стефан Шазелас
@StephaneChazelas Хороший вопрос, хотя не о локали. Опять же, не стесняйтесь редактировать, чтобы добавить точность, чтобы титры были вашими (по крайней мере, при редактировании истории).
Тенсибай
2
Готово. Этот ответ намного лучше, чем самый проголосовавший здесь. Это заслуживает большего количества голосов. Этот и другие ответы здесь обсуждались в разделе Почему использование цикла оболочки для обработки текста считается плохой практикой? что привело меня сюда.
Стефан Шазелас
6

Еще два варианта:

Поскольку topили htopмогут быть не установлены в небольших системах, просмотр /procвсегда возможен.

Даже в небольших системах вы найдете shell...

вариант! (Не только bash)

Это точно так же , чем lolotux сценарий , но без какой - либо вилки 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

Не забудьте двойную кавычку "$PROGNAME"! Смотрите комментарий Стефана Шазеля :

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

Не пытайтесь echo $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
Ф. Хаури
источник
Предполагается, что имена процессов не содержат пробела, табуляции :, обратной косой черты, подстановочных знаков или управляющих символов.
Стефан Шазелас
@ StephaneChazelas Спасибо! Я добавил [1-9]ранее *для подсчета только пронумерованных путей (нет self, ни thread-self)
Ф. Хаури
1
Синтаксис известен, но имена процессов - нет. По крайней мере, укажите ваши переменные . (в любом случае, ваш скрипт намного менее плох, чем loloxux ').
Стефан Шазелас
1
Имена процессов в Linux могут содержать любое значение байта, кроме 0, но его длина не должна превышать 15 байтов. NameЗапись в /proc/*/statusкодирует некоторые из этих значений байтов. Попробуйте, например perl -ne 'BEGIN{$0="\n\t\\"} print if /^Name/' /proc/self/status. Поскольку он настолько короткий, ущерб, который может быть нанесен такими вещами, perl -ne 'BEGIN{$0="/*/*/../../*/*"} print if /^Name/' /proc/self/statusограничен, если вы забудете процитировать свои переменные.
Стефан Шазелас
1
Это (по крайней мере , версия Perl , который я только что попробовал) является чрезвычайно быстрее , чем другие ответы.
Дэвид Гарднер
5

Я адаптировал другой сценарий в Интернете для этой длинной строки:

 { 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 и перенаправляю вывод в файл журнала. Информация здесь та же, что и при накоплении Swap:записей в файле 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.

Otheus
источник
2
Это хорошо, но первый сортирует по возрастанию pid (sort -n). Лучше использовать сортировку по использованию подкачки в порядке убывания (наиболее часто перед списком). Чтобы получить его, измените "sort -n" на "sort -n -k 3 -r"
Стэн Браевски,
3

В MacOSX вы также запускаете команду top, но вам нужно набрать «o», затем «vsize», а затем «ENTER».

Alexis
источник
2

Я полагаю, что вы могли бы получить хорошее предположение, запустив topи ища активные процессы, использующие много памяти. Делать это программно сложнее - просто посмотрите на бесконечные споры об эвристике убийцы Linux OOM.

Подкачка является функцией наличия большего количества памяти в активном использовании, чем установлено, поэтому обычно трудно обвинить это в одном процессе. Если это постоянная проблема, лучшим решением будет установка дополнительной памяти или внесение других системных изменений.

dmckee --- котенок экс-модератора
источник
1

Я не знаю ни одного прямого ответа о том, как точно определить, какой процесс использует пространство подкачки, однако эта ссылка может оказаться полезной . Еще один хороший здесь

Кроме того, используйте хороший инструмент, такой как htop, чтобы увидеть, какие процессы используют много памяти и сколько общего объема подкачки используется.

Жан Аззопарди
источник
1

iotopэто очень полезный инструмент. Он дает оперативную статистику ввода / вывода и использования свопа для процесса / потока. По умолчанию он показывает для потока, но вы можете сделать, iotop -Pчтобы получить информацию о процессе. Это не доступно по умолчанию. Возможно, вам придется установить через rpm / apt.

Сунил
источник
1

Вот версия, которая выводит то же самое, что и скрипт @loolotux, но намного быстрее (хотя и менее читабелен). Этот цикл занимает около 10 секунд на моей машине, моя версия занимает 0,019 с, что имело значение для меня, потому что я хотел превратить его в страницу 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

Начиная с исправления ядра 2015 года, которое добавляет SwapPss( https://lore.kernel.org/patchwork/patch/570506/ ), можно наконец получить пропорциональный счет подкачки, что означает, что если процесс поменялся много раз, а затем разветвился, оба разветвленных процесса будет сообщено о свопе на 50% каждый. И если любой из них затем разветвляется, то каждый процесс считается 33% переставленных страниц, поэтому, если вы посчитаете все эти операции подкачки вместе, вы получите реальное использование подкачки вместо значения, умноженного на количество процессов.

Коротко:

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

Первый столбец pid, второй столбец - использование свопа в КиБ, а остальная часть строки - выполнение команды. Идентичные числа свопа отсортированы по pid.

Выше могут испускать линии, такие как

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

это просто означает, что процесс с pid 15407 закончился между его отображением в списке /proc/и чтением smapsфайла процесса . Если это важно для вас, просто добавьте 2>/dev/nullв конец. Обратите внимание, что вы потенциально можете потерять любую другую возможную диагностику.

В примере с реальным миром это меняет другие инструменты, сообщающие о ~ 40 МБ использования подкачки для каждого дочернего элемента apache, работающего на одном сервере, на фактическое использование между 7-3630 КБ, реально используемыми для каждого дочернего элемента.

Микко Ранталайнен
источник