Правильное определение использования памяти в Linux


63

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

На моем сервере это результат free -m

[root@server ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          2048       2033         14          0         73       1398
-/+ buffers/cache:        561       1486
Swap:         2047         11       2036

Мое понимание того, как Linux управляет памятью, заключается в том, что она будет хранить информацию об использовании диска в оперативной памяти, чтобы каждый последующий доступ был быстрее. Я полагаю, что это указано в «кэшированных» столбцах. Кроме того, в ОЗУ хранятся различные буферы, указанные в столбце «буферы».

Так что, если я правильно понимаю, предполагается, что «фактическим» использованием будет «используется» значение «- / + buffers / cache», или 561 в этом случае.

Если предположить, что все это правильно, то часть, которая меня бросает, это результат ps aux.

Мое понимание psрезультатов заключается в том, что 6-й столбец (RSS) представляет размер в килобайтах, который процесс использует для памяти.

Поэтому, когда я запускаю эту команду:

[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52

Разве результат не должен быть "использованным" столбцом "- / + buffers / cache" из free -m?

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


Этот вопрос довольно популярен, и я думаю, что я должен поделиться ответом htopавтора на один похожий вопрос, который у меня был на днях ... Как рассчитать использование памяти из / proc / meminfo (как htop)
tgogos

Ответы:


58

Это точный и тот же вопрос был задан на ServerFault только другой день :-)

Система виртуальной памяти Linux не так проста. Вы не можете просто сложить все RSS поля и получить значение , указанное usedна free. Для этого есть много причин, но я выберу пару самых важных.

  • Когда процесс разветвляется, родитель и потомок будут показывать один и тот же RSS. Однако в Linux используется copy-on-writeтак, что оба процесса действительно используют одну и ту же память. Только когда один из процессов модифицирует память, он будет фактически дублирован. Таким образом, это приведет к тому, что freeчисло будет меньше topсуммы RSS.

  • Значение RSS не включает общую память. Поскольку общая память не принадлежит ни одному процессу, topне включает ее в RSS. Таким образом, это приведет к тому, что freeчисло будет больше topсуммы RSS.


1
Это лучший ответ, который я получил на любом сайте обмена стека на сегодняшний день. Так конкретно, что я хотел знать. Это особенно точно подходит для моей ситуации, потому что я имею дело с программой, которую я написал, которая разветвляется на процессы, но большая часть занимают библиотеки, которые они используют.
GoldenNewby

Проблема с этим ответом состоит в том, что вычисление суммы RSS и SHR часто дает намного меньше, чем используемая память. Например, на моем VPS используемая память составляет 380 МБ, а сумма всех RSS и SHR - 90 МБ.
user239558

2
@ user239558 Как я упоминал в ответе, есть много причин, по которым цифры не складываются, я перечислил только 2 из них. Есть много других номеров; кеш, плиты, огромные страницы и т. д.
Патрик

2
Вероятно, спустя годы после того, как вы ответили на это, у меня все еще есть (по крайней мере) одно замешательство. Вы сказали, что значение RSS не включает в себя общую память, но в этом ответе говорилось, что «оно включает в себя память из общих библиотек, пока страницы из этих библиотек фактически находятся в памяти». Теперь я не знаю, кому верить ... Может быть, мне здесь не хватает тонких различий ...
Naitree

1
@Naitree "разделяемые библиотеки"! = "Разделяемая память". общая память - это что-то вроде shmgetили mmap. Формулировка вокруг памяти очень хитрая. Использование неправильного слова в неправильном месте может полностью испортить значение предложения.
Патрик

30

Если вы ищете числа памяти, которые складываются, взгляните на смем :

Smem - это инструмент, который может предоставлять многочисленные отчеты об использовании памяти в системах Linux. В отличие от существующих инструментов, smem может сообщать о пропорциональном размере набора (PSS), который является более значимым представлением объема памяти, используемой библиотеками и приложениями в системе виртуальной памяти.

Поскольку большие части физической памяти обычно используются несколькими приложениями, стандартная мера использования памяти, известная как размер резидентного набора (RSS), значительно переоценивает использование памяти. Вместо этого PSS измеряет «справедливую долю» каждого приложения в каждой общей области, чтобы дать реалистичную оценку.

Например здесь:

# smem -t
  PID User     Command                         Swap      USS      PSS      RSS
...
10593 root     /usr/lib/chromium-browser/c        0    22868    26439    49364 
11500 root     /usr/lib/chromium-browser/c        0    22612    26486    49732 
10474 browser  /usr/lib/chromium-browser/c        0    39232    43806    61560 
 7777 user     /usr/lib/thunderbird/thunde        0    89652    91118   102756 
-------------------------------------------------------------------------------
  118 4                                       40364   594228   653873  1153092 

Так PSSже интересный столбец здесь, потому что он принимает во внимание общую память.
В отличие от RSSэтого имеет смысл добавить это. Мы получаем 654Mb всего для процессов пользователя.

Общесистемный вывод рассказывает об остальном:

# smem -tw
Area                           Used      Cache   Noncache 
firmware/hardware                 0          0          0 
kernel image                      0          0          0 
kernel dynamic memory        345784     297092      48692 
userspace memory             654056     181076     472980 
free memory                   15828      15828          0 
----------------------------------------------------------
                            1015668     493996     521672 

Так 1Gb общий RAM = 654Mb пользовательского уровня процессов + 346Mb ядра MEM + 16Mb бесплатно
(дать или взять несколько Mb)

В целом около половины памяти используется для кэша (494 МБ).

Бонусный вопрос : что здесь такое кеш пользователя или кеш ядра?


Кстати, что-то визуальное попробуйте:

# smem  --pie=name

введите описание изображения здесь


14

Действительно хороший инструмент - pmapэто список текущего использования памяти для определенного процесса:

pmap -d PID

Более подробную информацию об этом смотрите на странице руководства, man pmapа также посмотрите на 20 инструментов мониторинга системы Linux , которые должен знать каждый SysAdmin , в которых перечислены замечательные инструменты, которые я всегда использую для получения информации о моем Linux-боксе.


Это довольно крутой инструмент, но он не решает мою проблему. Я пытаюсь выяснить, как эффективно определить «фактическое» использование памяти на сервере.
GoldenNewby

3
@GoldenNewby Нет такого понятия, как «фактическое» использование памяти процессом. Фактическое использование памяти системы - это то, что freeговорит вам.
«SO- перестать быть злым» Жиля

pmap -x PIDтакже включает в себя колонку RSS, которая часто весьма полезна, чтобы понять, откуда topберется сумма RSS процесса (как видно, например, через via ).
maxschlepzig

10

Запустите top, нажмите hдля справки, fчтобы добавить поля. Вы можете добавить следующие поля:

  • RSS объем физической памяти, используемой приложением
  • CODE общий объем памяти, который использует исполняемый код процесса
  • DATA - общий объем памяти (КБ), выделенный для данных и стека процесса

Между этими 3 у вас должны быть довольно точные результаты. Вы также можете использовать более подробные замены для верхней я рекомендую htopили atop.

Изменить: почти забыл, если вы хотите действительно подробную информацию. Найдите PID и введите следующий файл.

PID=123

cat /proc/123/status

Изменить 2: Если вы можете найти его или получить книгу:

Оптимизация производительности Linux: практическое руководство по инструментам производительности Linux

- имеет раздел Глава 5: Инструменты производительности: память, специфичная для процесса - в нем гораздо больше информации, чем вы когда-либо хотели.


Ну top по умолчанию имеет размер RSS процесса. Top дает такие же результаты, как и «ps aux» в моем примере. У меня вопрос, как получается, что объединенный RSS всех процессов намного выше, чем «активное» использование памяти на всем сервере?
GoldenNewby

5

psдает вам объем памяти, используемый каждым процессом. Часть этой памяти - это mmapped файлы, которые учитываются в кеше. Часть этой памяти (особенно код) используется совместно с другими процессами, поэтому, если вы сложите значения RSS, она будет подсчитана несколько раз.

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


4

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

Если вы экспериментатор, вы можете запустить valgrind и массив . Это может быть немного тяжелым для обычного пользователя, но вы со временем получите представление о поведении памяти в приложении. Если приложение malloc () именно то, что ему нужно, это даст вам хорошее представление о реальном динамическом использовании памяти процессом. Но этот эксперимент можно «отравить».

Чтобы усложнить ситуацию, Linux позволяет вам перегружать память. Когда вы используете malloc () памяти, вы заявляете о своем намерении использовать память. Но на самом деле распределение не происходит до тех пор, пока вы не напишите байт на новую страницу вашего выделенного «ОЗУ». Вы можете доказать это себе, написав и запустив небольшую C-программу, например:

// test.c
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    void *p;
    sleep(5)
    p = malloc(16ULL*1024*1024*1024);
    printf("p = %p\n", p);
    sleep(30);
    return 0;
}

# Shell:
cc test.c -o test && ./test &
top -p $!

Запустите это на машине с менее чем 16 ГБ ОЗУ и, вуаля!, Вы только что набрали 16 ГБ памяти! (нет, не совсем).

Обратите внимание, что topвы видите «VIRT» как 16.004G, но% MEM равен 0.0

Запустите это снова с valgrind:

# Shell:
valgrind --tool=massif ./test &
sleep 36
ms_print massif.out.$! | head -n 30

И массив говорит "сумма всех allocs () = 16GB". Так что это не очень интересно.

НО, если вы запустите его в нормальном процессе:

# Shell:
rm test test.o
valgrind --tool=massif cc test.c -o test &
sleep 3
ms_print massif.out.$! | head -n 30

--------------------------------------------------------------------------------
Command:            cc test.c -o test
Massif arguments:   (none)
ms_print arguments: massif.out.23988
--------------------------------------------------------------------------------


    KB
77.33^                                                                       :
     |                                                                      #:
     |                                                                :@::@:#:
     |                                                           :::::@@::@:#:
     |                                                         @:: :::@@::@:#:
     |                                                     ::::@:: :::@@::@:#:
     |                                             ::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                      :@@@@@@@@@@@@@@@@@@@@:@::@:::@:::::@:: :::@@::@:#:
     |                      :@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |              :@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |          :::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |        :::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
   0 +----------------------------------------------------------------------->Mi
     0                                                                   1.140

И здесь мы видим (очень эмпирически и с очень высокой достоверностью), что компилятор выделил 77KB кучи.

Зачем так стараться, чтобы использовать только кучу? Потому что все общие объекты и текстовые разделы, которые использует процесс (в данном примере, компилятор), не очень интересны. Они постоянные накладные расходы на процесс. Фактически, последующие вызовы процесса почти приходят бесплатно.

Кроме того, сравните и сопоставьте следующее:

MMAP () файл объемом 1 ГБ. Ваш VMSize будет 1 + ГБ. Но ваш размер резидентного набора будет только теми частями файла, в который вы были помещены (путем разыменования указателя на этот регион). И если вы «прочитаете» весь файл, то к тому времени, когда вы дойдете до конца, ядро, возможно, уже выровняло начало (это легко сделать, потому что ядро ​​точно знает, как / где заменить эти страницы, если разыменоваться снова ). В любом случае, ни VMSize, ни RSS не являются хорошим индикатором использования вашей памяти. Вы на самом деле ничего не использовали malloc ().

В отличие от Malloc () и коснитесь много памяти - пока ваша память не будет перенесена на диск. Таким образом, ваша выделенная память теперь превышает ваши RSS. Здесь ваш VMSize может начать вам что-то говорить (вашему процессу принадлежит больше памяти, чем на самом деле находится в вашей памяти). Но все еще трудно различить ВМ, которая является общими страницами, и ВМ, которая обменивается данными.

Это где Вальгринд / массив становится интересным. Он показывает, что вы намеренно распределили (независимо от состояния ваших страниц).


У меня есть к вам вопрос. У меня есть процесс, который mlock () все его файлы mmap. Есть ли способ определить, сколько этой памяти активно используется - сколько из нее было прочитано или записано, скажем, в последние минуты или две?
Майкл Мартинес

2

Попробуйте это: он даст вам общий объем оперативной памяти, фактически используемый всеми процессами, выполняющимися в МБ

ps -eo size,pid,user,command --sort -size | awk '
  { hr=$1/1024 ; printf("%13.2f Mb ",hr) } 
  { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }
  ' | awk '{total=total + $1} END {print total}'

sizeСообщил psимеет мало отношения к фактическому использованию памяти. Это виртуальный размер каждого процесса, который не обязательно выделяется из памяти. Это также не включает некоторые сегменты, которые выделены.
Мэтт

-2

Это покажет вам, сколько памяти пользователя пользователями.

#!/bin/bash
total_mem=0

printf "%-10s%-10s\n" User MemUsage

while read u m
do
        [[ $old_user != $u ]] && {  printf "%-10s%-0.1f\n" $old_user $total_mem;
                                    total_mem=0; }
        total_mem="$(echo $m + $total_mem | bc)"
        old_user=$u

done < <(ps --no-headers -eo user,%mem| sort -k1)

#EOF

-3

Используйте эту команду, чтобы найти использование памяти в%.

Используемая память:

grep Mem | awk '{print $3/$2 * 100.0}'

свободная память

grep Mem | awk '{print $4/$2 * 100.0}'

3
Э-э, это ничего не сделает. grepбудет просто сидеть там в ожидании ввода.
mattdm

1
Это должно было бытьfree -m | grep Mem | awk '{print $3/$2 * 100.0}'
vjangus
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.