digiwhite 12.02.2010 21:52

НовичкуКак ядро Linux работает с оперативной памятью

Забавно, но читая флеймообразующий пост под авторством пользователя LiS-31 обратил внимание на комментарии пользователя HTaeD по поводу использования браузера Uzbl. Ссылочка от того же пользователя отправила меня в F.A.Q. от создателей сего браузера, который я сел читать в электричке по пути на работу. Интересно, что в F.A.Q.е я увидел вопрос, звучащий так:"Uzbl использует слишком много памяти! Особенно, когда работает в многооконном режиме (т.е. когда используются вкладки)". Авторы Uzbl дали такой ответ:
Не дайте себя обмануть тем, как утилиты Linux показывают вам измеренное количество использованной памяти. Вы должны понимать как разницу между RSS (Resident Set Size) и VSS (Virtual Set Size), так и то, что динамические библиотеки (libwebkit, libgtk и т.д.) загружаются в память лишь однажды.

И далее авторы дают ссылку на интересную статью, объясняющую суть того, как же все таки ядро Linux работает с оперативной памятью.

Таки образом я решил сделать перевод этой статьи, так как уверен, что она будет полезна не только новичками (хоть и размещена в этом блоге). Итак.


Как ядро Linux работает с оперативной памятью

Эта небольшая статья предназначена для тех, кто хотя бы раз удивленно спрашивал себя нечто в стиле: "Какого черта простой текстовый редактор KDE занимает 25 Мб в оперативной памяти?" Множество людей уверовали в то, что приложения Linux, особенно входящие в состав KDE или Gnome, являются "раздутыми" или "тяжеловесными", основываясь только лишь на выводе утилит, подобных ps. Этот вывод может соответствовать действительности, а может и нет, это зависит от самой программы, но чаще всего - этот вывод ошибочен, т.к. на самом деле множество программ используют память намного эффективнее, чем это кажется.


О чем сообщает утилита ps

Утилита ps может выводить различную информацию о процессе, например такую как идентификатор процесса, его текущее состояние, то, как он(процесс) использует ресурсы. Так же возможным является вывод параметров VSZ(Virtual Set Size) и RSS(Resident Set Size).
VSZ показывает, сколько виртуальной памяти выделено под процесс, а RSS показывает, сколько страниц физической(оперативной) памяти выделено под процесс. *примечание переводчика, т.е. меня :)

В основном, эти два параметра используются "гиками" по всему миру для того, чтобы определить сколько памяти потребляет процесс.


В качестве примера давайте посмотрим на вывод команды ps aux на моем компьютере (вывод размеется урезан. *прим. переводчика):
1
2
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
dbunker 3468 0.0 2.7 25400 14452 ? S 20:19 0:00 kdeinit: kedit



Судя по выводу утилиты ps, KEdit занимает порядка 25 Мб в области VSS и порядка 14 Мб в области RSS (оба значения показываются в килобайтах). Похоже, что большинству людей нравится наугад выбрать одно из значений как значение, реально отражающее потребление процессом оперативной памяти. Я не буду сейчас раскрывать суть различий между VSZ и RSS, не говоря уже о том, что такой подход в определении размера занимаемой процессом памяти ошибочен. Ни то ни другое значение в точности не отображают реально занимаемой памяти программой KEdit.


Почему использование утилиты ps ошибочно?

В зависимости от того, как вы на это смотрите, ps не сообщает размер реально занимаемой процессом памяти. Что эта утилита действительно делает, так это показывает сколько каждый процесс займет памяти в случае, как будто если бы он был единственным запущенным процессом. Разумеется, что обычно это не так и типичный компьютер под управлением Linux имеет несколько десятков процессов, работающих одновременно, что говорит о том, что значения VSZ и RSS, которые отображает утилита ps наверняка ошибочны. Для того чтобы понять, почему это так, необходимо понять как Linux управляет разделяемыми (динамически загружаемыми) библиотеками в контексте программ.

Большинство программ в Linux используют разделяемые библиотеки для использования реализованной в этих библиотеках функциональности. Например, текстовый редактор KDE использует несколько разделяемых библиотек KDE (для реализации возможностей взаимодейстовия с другими частями KDE), несколько библиотек X (для реализации возможностей отображения изображений и вставки/копирования из/в буфер) и основных системных библиотек (для того чтобы иметь возможность выполнять базовые операции). Многие из этих разделяемых библиотек, особенно такие часто используемые как libc, используются многими программами, запускаемых в Linux системах. Из-за этого совместного использования Linux использует следующий трюк: ядро загружает единственную копию разделяемой библиотеки в память и использует эту копию для каждой программы, которая нуждается в этой библиотеке.

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

К сожалению, достичь корректного отображения используемой процессом памяти не так просто. Требуется понимать не только то, как действительно работает система, но и решить несколько сложных вопросов. Должен ли размер памяти, занимаемой разделяемой библиотекой, необходимой только одному процессу учитываться в подсчете размера памяти занимаемой данным процессом? Если разделяемая библиотека используется множеством процессов, должна ли память занимаемая ей, быть равномерно распределена среди процессов ее использующих или же размер занимаемой памяти должен быть проигнорирован и не учтен? Здесь нет быстрого и однозначного решения: у вас должны быть различные ответы в зависимости от ситуации, с которой вы столкнулись. Теперь легко понять, почему утилита ps не пытается выдать однозначно "правильный" отчет об используемой процессом памяти, а выдает двусмысленный результат.


Карта памяти процесса

Достаточно разговоров. Давайте посмотрим, почему KEdit занимает так много памяти. Для того чтобы увидеть, как выглядит память процесса KEdit мы будем использовать утилиту pmap (с флагом -d):

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Address   Kbytes Mode  Offset           Device    Mapping
08048000 40 r-x-- 0000000000000000 0fe:00000 kdeinit
08052000 4 rw--- 0000000000009000 0fe:00000 kdeinit
08053000 1164 rw--- 0000000008053000 000:00000 < anon >
40000000 84 r-x-- 0000000000000000 0fe:00000 ld-2.3.5.so
40015000 8 rw--- 0000000000014000 0fe:00000 ld-2.3.5.so
40017000 4 rw--- 0000000040017000 000:00000 < anon >
40018000 4 r-x-- 0000000000000000 0fe:00000 kedit.so
40019000 4 rw--- 0000000000000000 0fe:00000 kedit.so
40027000 252 r-x-- 0000000000000000 0fe:00000 libkparts.so.2.1.0
40066000 20 rw--- 000000000003e000 0fe:00000 libkparts.so.2.1.0
4006b000 3108 r-x-- 0000000000000000 0fe:00000 libkio.so.4.2.0
40374000 116 rw--- 0000000000309000 0fe:00000 libkio.so.4.2.0
40391000 8 rw--- 0000000040391000 000:00000 < anon >
40393000 2644 r-x-- 0000000000000000 0fe:00000 libkdeui.so.4.2.0
40628000 164 rw--- 0000000000295000 0fe:00000 libkdeui.so.4.2.0
40651000 4 rw--- 0000000040651000 000:00000 < anon >
40652000 100 r-x-- 0000000000000000 0fe:00000 libkdesu.so.4.2.0
4066b000 4 rw--- 0000000000019000 0fe:00000 libkdesu.so.4.2.0
4066c000 68 r-x-- 0000000000000000 0fe:00000 libkwalletclient.so.1.0.0
4067d000 4 rw--- 0000000000011000 0fe:00000 libkwalletclient.so.1.0.0
4067e000 4 rw--- 000000004067e000 000:00000 < anon >
4067f000 2148 r-x-- 0000000000000000 0fe:00000 libkdecore.so.4.2.0
40898000 64 rw--- 0000000000219000 0fe:00000 libkdecore.so.4.2.0
408a8000 8 rw--- 00000000408a8000 000:00000 < anon >
... (trimmed) ...
mapped: 25404K writeable/private: 2432K shared: 0K



Я убрал большую часть вывода: то что осталось, показано выше. Даже без полного вывода информации мы можем увидеть несколько очень интересных вещей. Первый важный момент, который надо отметить, это то, что каждая разделяемая библиотека отображается дважды; первый раз - это сегмент кода, второй раз - это сегмент данных. Сегмент кода имеет режим доступа "r-x--" (владелец(создатель) процесса может выполнять и читать сегмент кода. *прим. переводчика), в то время как сегмент данных имеет режим доступа "rw---" (владелец(создатель) процесса может читать из и писать в сегмент данных. *прим. переводчика). Интерес для нас будут представлять только столбцы KBytes, Mode и Mapping, все остальное в нашем случае не представляет интереса для нашего обсуждения.

Если вы просмотрите вывод, вы увидите что строки с самым большим значением в столбце KBytes обычно принадлежат кодовому сегменту, содержащемуся в разделяемых библиотеках (их имена начинаются с префикса "lib"). Важно отметить, что только кодовый сегмент может быть совместно использован различными процессами. Если убрать все кодовые сегменты и посчитать память, занимаемую только сегментами данных (с режимом доступа "rw---", то мы получим значение, записанное как writeable/private. Это значение как раз можно рассматривать как память, занимаемую процессом без учета памяти, занимаемой разделяемыми библиотеками. Поэтому, цена, которую мы заплатим за запуск экземпляра KEdit (предполагая, что все разделяемые библиотеки уже загружены) составит чуть больше 2 Мб. А это очень сильно отличается от 14 и 25 Мб, о которых нам сообщала утилита ps.


И что это все значит?

Мораль данной истории такова, что размер памяти, занимаемой процессом в Linux - это многогранный вопрос. Вы не можете просто запустить утилиту ps и узнать, что происходит. Особенно это верно в случае, когда вы имеете дело с программами, которые создают множество дочерних процессов (например Apache). ps может сообщать, что каждый процесс Apache занимает 10 Мб оперативной памяти, когда на самом деле, по максимуму, он занимает 1 Мб. Эта информация становится критичной тогда, когда вы настраиваете параметр MaxClients для Apache, который определяет как много одновременных подключений сервер может обработать.

Так же, это показывает, почему лучше придерживаться "однотипных" приложений на рабочем столе на столько, насколько это возможно. Если вы используете KDE в качестве рабочего окружения, но при этом в основном пользуетесь приложениями Gnome, то вы платите высокую цену за множество избыточных (но разных) разделяемых библиотек. Придерживаясь насколько это возможно в использовании только приложений KDE или Gnome, в целом, вы уменьшаете общее количество используемой оперативной памяти из-за уменьшения количества памяти используемой под вновь запускаемые приложения KDE или Gnome, что позволяет Linux использовать больше памяти для других интересных вещей (например кэширование файлов, сильно ускоряющего доступ к фалам).


Оригинал статьи: http://virtualthreads.blogspot.com/2006/02/understanding-memory-usage-on-linux.html
Перевод: digiwhite


Тэги: Linux memory pmap ram rss vsz линукс новичку память перевод
+ 43 -
Похожие Поделиться

HTaeD 12.02.2010 22:18 #
Спасибо за качественный перевод. Очень интересно почитать.
digiwhite 12.02.2010 22:19 #
Рад, что понравилось и, что стилистика не совсем ужасна :)
Restless 12.02.2010 22:22 #
очень познавательно. спасибо.
я давно подозревал, что что-то не так в этом вашем линуксе :)
chemikadze 12.02.2010 22:26 #
Малаццом =)
pioner14 12.02.2010 22:36 #
Очень интересно! Спасибо!
cubiccat 12.02.2010 22:36 #
Познавательно
dementiy 12.02.2010 22:38 #
Действительно спасибо за хороший перевод. На счет отображения памяти с помощью ps, точнее top/htop, мне кажется был бы интересным такой подход: вывод процессов без учета занимаемой памяти библиотеками, выбираем интересующий нас процесс и раскрывается список библиотек, используемых процессом с количеством занимаемой памяти каждой библиотекой и ссылок - сколько еще процессов используют данную библиотеку.
digiwhite 12.02.2010 22:44 #
Честно говоря, особо про работу top/htop ничего не знаю. Было бы интересно почитать обзор о том, как работать с данной утилитой "на полную".
dementiy 12.02.2010 23:01 #
А что значит "на полную"? К примеру htop выводит информацию о процессах, потребляемой памяти, загруженности процессоров и т.д., а если говорить о "конкретных" действиях, то он умеет убивать процессы (точнее посылать им различные сигналы) и менять приоритет процесса.
digiwhite 12.02.2010 23:05 #
Он поддерживает некоторый набор команд. Когда запустите top, нажмите h.
Shtsh 12.02.2010 23:36 #
Хороший материал - познавательный. И перевод замечательный
assaron 13.02.2010 00:00 #
не раскрыта тема потребления памяти uzbl'ом :)
digiwhite 13.02.2010 00:03 #
Речь не о нем вообще :) Это предыстория о том, как я вышел на статью перевод которой здесь и написал.

ЗЫ: мораль такова, что даже флеймотопики бывают иногда полезны :)
Shtsh 13.02.2010 00:09 #
На самом деле, во флеймотопиках полезной информации очень много. Только нужно уметь вычленять её из флейма
ginz 13.02.2010 00:51 #
Спасибо за материал.
Aineko 13.02.2010 02:06 #
можно скрипт написать, выдающий реальный размер памяти, используемые библиотеки.
digiwhite 13.02.2010 09:13 #
. Если убрать все кодовые сегменты и посчитать память, занимаемую только сегментами данных (с режимом доступа "rw---", то мы получим значение, записанное как writeable/private. Это значение как раз можно рассматривать как память, занимаемую процессом без учета памяти, занимаемой разделяемыми библиотеками.

Скрипт написать можно, но я согласен с автором, что не все так однозначно. Можно конечно опять же выдвать сразу два значения. Первое - учитывающее память занимаемую разделяемыми библиотеками, второе не учитывающее.
NutipA 13.02.2010 02:12 #
Спасибо большое, очень полезно. А кто может рассказать для полноты картины как отображает потребление памяти виндовый диспетчер задач?
assaron 13.02.2010 17:46 #
если не ошибаюсь, то он показывает что-то типа RSS
Donat 13.02.2010 12:40 #
Отличная статья.
xtavras 13.02.2010 22:12 #
Хм, только сейчас увидел что пользователя нельзя уже плюсовать через профиль,давно убрали? а то перевод уж больно хорош)
digiwhite 13.02.2010 22:25 #
Спасибо :).
Только что перечитал весь пост, нашел кое-какие стилистические ошибки, несколько опечаток и таки в одно слово все-таки залезло "падонкавскае" звучание :). Разумеется пофиксил все.
m039 15.02.2010 14:00 #
Спасибо, прочитал, теперь возникло больше вопросов, на которые в статье не дано ответов. После чего начал делать запросы в гугле, на что выдало следующую ссылку. :)
digiwhite 15.02.2010 15:23 #
Бгг. Ну теперь можно сравнить два независимых перевода и найти истину где-то по середине :)