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

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

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

На моем сервере это результат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 управляет памятью, он будет хранить использование диска в ОЗУ, чтобы каждый последующий доступ был быстрее. Я полагаю, что это указано в столбцах "cached". Кроме того, в ОЗУ хранятся различные буферы, указанные в столбце "buffers".

Итак, если я правильно понимаю, «фактическое» использование должно быть «использованным» значением «-/+ буферов/кэша», или 561 в данном случае.

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

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

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

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

Разве результатом не должен быть столбец «использовано» из «-/+ буферов/кэша» free -m?

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

решение1

Бесстыдно копирую/вставляю свой ответ изошибка серверабуквально на днях :-)

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

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

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

Есть много других причин, по которым цифры могут не сходиться. Этот ответ просто пытается показать, что управление памятью очень сложно, и вы не можете просто сложить/вычесть отдельные значения, чтобы получить общее использование памяти.

решение2

Если вы ищете цифры памяти, которые суммируются, посмотритесмэм:

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него имеет смысл суммировать его. Мы получаем 654 Мб всего для процессов пользовательского пространства здесь.

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

# 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 

Итак, 1 ГБ оперативной памяти в целом = 654 МБ пользовательских процессов + 346 МБ памяти ядра + 16 МБ свободной
(с погрешностью в несколько МБ)

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

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


кстати, для наглядности попробуйте:

# smem  --pie=name

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

решение3

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

pmap -d PID

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

решение4

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

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

Чтобы усложнить ситуацию, Linux позволяет вампереобязательствовашу память. Когда вы делаете malloc() памяти, вы заявляете о своем намерении использовать память. Но выделение на самом деле не происходит, пока вы не запишете байт в новую страницу вашей выделенной "RAM". Вы можете убедиться в этом сами, написав и запустив небольшую программу на 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

А massif говорит "sum of all 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

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

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

Также сравните и сопоставьте следующее:

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

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

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

Связанный контент