Новичку — Как ядро Linux работает с оперативной памятью
Забавно, но читая флеймообразующий пост под авторством пользователя LiS-31 обратил внимание на комментарии пользователя HTaeD по поводу использования браузера Uzbl. Ссылочка от того же пользователя отправила меня в F.A.Q. от создателей сего браузера, который я сел читать в электричке по пути на работу. Интересно, что в F.A.Q.е я увидел вопрос, звучащий так:"Uzbl использует слишком много памяти! Особенно, когда работает в многооконном режиме (т.е. когда используются вкладки)". Авторы Uzbl дали такой ответ:
И далее авторы дают ссылку на интересную статью, объясняющую суть того, как же все таки ядро Linux работает с оперативной памятью.
Таки образом я решил сделать перевод этой статьи, так как уверен, что она будет полезна не только новичками (хоть и размещена в этом блоге). Итак.
Как ядро Linux работает с оперативной памятью
Эта небольшая статья предназначена для тех, кто хотя бы раз удивленно спрашивал себя нечто в стиле: "Какого черта простой текстовый редактор KDE занимает 25 Мб в оперативной памяти?" Множество людей уверовали в то, что приложения Linux, особенно входящие в состав KDE или Gnome, являются "раздутыми" или "тяжеловесными", основываясь только лишь на выводе утилит, подобных ps. Этот вывод может соответствовать действительности, а может и нет, это зависит от самой программы, но чаще всего - этот вывод ошибочен, т.к. на самом деле множество программ используют память намного эффективнее, чем это кажется.
О чем сообщает утилита ps
Утилита ps может выводить различную информацию о процессе, например такую как идентификатор процесса, его текущее состояние, то, как он(процесс) использует ресурсы. Так же возможным является вывод параметров VSZ(Virtual Set Size) и RSS(Resident Set Size).
В основном, эти два параметра используются "гиками" по всему миру для того, чтобы определить сколько памяти потребляет процесс.
В качестве примера давайте посмотрим на вывод команды ps aux на моем компьютере (вывод размеется урезан. *прим. переводчика):
Судя по выводу утилиты 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):
Я убрал большую часть вывода: то что осталось, показано выше. Даже без полного вывода информации мы можем увидеть несколько очень интересных вещей. Первый важный момент, который надо отметить, это то, что каждая разделяемая библиотека отображается дважды; первый раз - это сегмент кода, второй раз - это сегмент данных. Сегмент кода имеет режим доступа "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 показывают вам измеренное количество использованной памяти. Вы должны понимать как разницу между 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 |
Судя по выводу утилиты 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 28 29 |
|
Я убрал большую часть вывода: то что осталось, показано выше. Даже без полного вывода информации мы можем увидеть несколько очень интересных вещей. Первый важный момент, который надо отметить, это то, что каждая разделяемая библиотека отображается дважды; первый раз - это сегмент кода, второй раз - это сегмент данных. Сегмент кода имеет режим доступа "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