Як дізнатися, які процеси використовують swap-простір в Linux?


240

Як дізнатися, який процес використовує простір swap більше в Linux?


30
Ваша прийнята відповідь неправильна. Подумайте про зміну його на відповідь lolotux, що насправді правильно.
jterrace

@jterrace вірно, у мене немає стільки місця підкачки, скільки суми значень у стовпці SWAP вгорі.
акостадінов

1
iotop - дуже корисна команда, яка показуватиме статистику живого використання io та swap за процес / потік
sunil

@jterrace, подумайте, чий прийнятий відповідь дня невірний. Через шість років ми з рештою не знаємо, чи ви мали на увазі відповідь Девіда Холма (прийнята на сьогодні) чи якусь іншу відповідь. (Ну, я бачу, ви також сказали, що відповідь Девіда Холма невірна, як коментар до його відповіді ... так що, мабуть, ви, мабуть, мали на увазі його.)
Дон Хетч

Відповіді:


106

Запустіть верх, а потім натисніть OpEnter. Тепер процеси слід сортувати за їхнім використанням.

Ось оновлення, оскільки моя оригінальна відповідь не дає точної відповіді на проблему, як зазначено в коментарях. Із поширених запитань htop :

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


137
З документів, стовпець SWAP вгорі, здається, просто показує, який обмін необхідним буде, якщо весь процес замінено, а не те, наскільки фактично замінено процес. З того, що я можу сказати після короткого пошуку, немає ніякого способу визначити, яка частина кожного процесу витісняється на даний момент. Автор htop відмовляється ставити такий стовпець через це (я бачу стовпці CNSWAP і NSWAP, але вони, схоже, нічого не роблять на моїй машині): htop.sourceforge.net/index.php?page=faq
yukondude

6
@yukondude вірно, стовпець SWAP вгорі просто VIRT - RES, і ця інформація в цьому контексті є марною. Наприклад, немає жодної компенсації, наприклад, для спільної пам'яті відображеної відео оперативної пам'яті. Також процес не міг посилатися на всю пам'ять. У цьому випадку ОС не обов'язково зчитувати повний бінарний файл з диска в пам'ять, і, таким чином, значення ВДЕ не включає цю частину пам'яті.
Барт

Я б підтримав це більше, якби міг. Це рятує мій бекон!
atrain

На щастя, це коментарі до @jterrace :) (хоча, мабуть, ви повинні їх прочитати: S ... не впевнений, на що йдеться, я сподіваюся, що це yukondude)
AJP

11
Що стосується того, що коментар більше не працює: схоже, що в останніх версіях верху більше не встановлено "O" в якості ключа для вибору полів сортування. При використанні? Ви можете побачити власне ім'я програми та версію програми, пропс-нг - остання версія. Це виделка 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"

Ось копія, якщо посилання вмирає: 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; вашому будку може чогось бракувати.
tuk0z

1
Будь ласка, подивіться на мою версію цього сценарію без вилки !
Ф. Хаурі

3
У автора є наступний пост про те, як це зробити за допомогою top: northmost.org/blog/swap-usage-5-years-later
Jack 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}/";

2
Дуже приємний сценарій. Він дає ту саму інформацію, що і lolotux, але краще читається.
Філіп Вендлер

Відмінний вихід. Дякую.
Брайан Клайн

2
Єдине , що я змінив використовував argsзамість commв psкоманді , так як у мене є багато процесів , з тим же ім'ям , але з різними аргументами (зв'язка пітон gunicorn процесів). Тобто:ps -p $PID -o args --no-headers
mgalgs

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/


Це добре. Ось адаптована версія з цієї статті, щоб показати документи, відсортовані за допомогою swap-використання з доданим PID: $ for file in / proc / * / status; do awk '/ ^ Pid | VmSwap | Назва / {printf $ 2 "" $ 3} END {print ""}' $ файл; зроблено | сортувати -k 3 -n -r | менше
Stan Brajewski

Ви повинні glob / proc / [1-9] * / статус, щоб виключити пару спеціальних записів / proc, і ви можете комбінувати аргументи сортування як -rnk3
dland

10

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

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


6

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


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.

Я сподіваюся, що я прокоментував код достатньо, щоб сказати, що він робить.


1
Зауважте, що bashрозгортається каталоги впорядкованим способом (лексичним, а не числовим). Випадковий порядок зводиться до того, як awkзберігає свої масиви (хеш-таблицю) та як for p in pnameїх отримує.
Стефан Хазелас

@StephaneChazelas Ну, це навіть не лексика, це сортування коду ascii (як це /proc/1/statusвідбувається після того, /proc/1992/statusщо у /коду ascii вище коду 9 ascii. Це дає вигляд і відчуття "випадкового порядку". Я згоден з таблицею awk хешу , Я взяв ярлик тут. Не соромтесь редагувати відповідь, щоб зберегти атрибуцію в історії редагування
Tensibai

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...

А варіант! (Тільки не башти)

Це точно так само, як скрипт 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, сума swap. У вищенаведеній версії trсмужки нечислових компонентів. В обох випадках вихід сортується чисельно за допомогою pid.


2
Це добре, але перший сортує за pid висхідним (сортування -n). Краще використання - це його сортування за допомогою заміни в порядку зменшення (найбільше - перед списком). Щоб змінити "сортувати -n" на "сортувати -n -k 3 -r"
Stan Brajewski

3

На MacOSX ви також запускаєте верхню команду, але потрібно ввести "o", а потім "vsize", а потім ENTER.


2

Я припускаю, що ви можете добре здогадатися, запустивши topта шукаючи активні процеси, використовуючи багато пам’яті. Зробити це програмно важче --- просто подивіться на нескінченні дискусії про евристику вбивць Linux OOM.

Перекачування є функцією , що мають більше пам'яті в активному використанні , ніж встановлений, так що, як правило , важко звинуватити в цьому єдиному процесі. Якщо це проблема триває, найкраще рішення - встановити більше пам'яті або внести інші системні зміни.



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, другий стовпчик - це використання своп у KiB, а решта рядка - команда виконується. Ідентичні підрахунки свопів сортуються за pid.

Вище може випромінювати рядки типу

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

що просто означає, що процес з підпискою 15407 закінчився між переглядом його у списку /proc/та читанням smapsфайлу процесу . Якщо це має значення для вас, просто додайте 2>/dev/nullдо кінця. Зверніть увагу, що ви також потенційно втратите будь-яку іншу можливу діагностику.

У прикладі реального світу це змінює використання інших інструментів звітування ~ 40 Мб використання свопів для кожної дитини апаша, що працює на одному сервері, на фактичне використання від 7-3630 Кб, дійсно використане на одну дитину.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.