8.5 Устранение проблем, связанных с виртуальной памятью

Предыдущая  Содержание  Следующая V*D*V

При запуске приложения на Linux пользователь часто сталкивается с проблемами управления памятью. Они могут быть условно разделены на три категории:

 

Утечки памяти: утечки памяти возникают, когда кусок памяти, который был выделен, не освобождается. Повторяющиеся утечки памяти могут оказаться фатальными для встраиваемых систем, потому что система не сможет работать при нехватке памяти.

Переполнение: переполнение является состоянием, при котором происходит обращение к адресам за пределами выделенной области памяти. Переполнение представляет собой очень серьёзную угрозу для безопасности и используется злоумышленниками для взлома системы.

Повреждение: повреждение памяти происходит, когда указатели памяти содержат неправильные или недостоверные значения. Использование таких указателей может привести к нарушению работы программы и обычно ведёт к завершению программы.

 

Проблемы управления памятью очень тяжелы для поиска, в том смысле, что их очень трудно найти с помощью проверки кода, и они могут происходить или непостоянно, или после многих часов использования системы. К счастью, для отслеживания проблем, связанных с управлением памятью, есть ряд инструментов с открытым исходным кодом. В следующих подразделах о них рассказывается подробно с соответствующими примерами. Выделение динамической памяти в Linux рассматривается в Главе 10.

Утечки памяти связаны прежде всего с двумя причинами:

 

Небрежность автора кода: разработчик программы не обращает должного внимания на освобождение выделенной памяти, когда она больше не используется.

Повреждение указателя: это происходит, когда указатель, содержащий ссылку на фрагмент памяти, повреждается, следовательно, теряется ссылка на кусок памяти.

 

Повторные утечки памяти на встроенной системе, не имеющей подкачки, заставляют систему испытывать недостаток памяти. Как в таком случае ведёт себя система? Когда системе начинает не хватать памяти, она переходит в режим урезания (prune mode) и пытается сжать системные кэши (например, кэш страниц, кэш буферов и кэши файловой системы, а также кэши кусков памяти) и в этом процессе освобождается от файлов образа процесса. Если даже по завершении этой работы системе не хватает памяти, вызывается печально известное сообщении о недостатке памяти (out of memory) или убийца OOM. Когда вызывается OOM, вы видите в консоли следующее сообщение:

 

Out of Memory: Killed process 10(iisd)

 

В этом случае убийца OOM убил процесс iisd (с pid 10). Убийцу OOM в ядро версии 2.2.15 добавил Рик Ван Рейл. В основе философии убийцы OMM лежит то, что когда в системе мало памяти, вместо того, чтобы позволить ядру паниковать или вызвать блокировку системы, лучше убить процесс или набор процессов, чтобы снова вернуть системе память. Поэтому вместо того, чтобы дать системе упасть, дайте ей работать с одним или несколькими убитыми приложениями. Очевидно, что ключом к реализации ООМ является выбор процесса, который будет убит; убийство важных общесистемных процессов может быть столь же вредным, как и падение системы. Следовательно убийца OOM был очень обсуждаемой темой, в особенности потому что очень трудно найти универсальное решение, так как Linux работает на очень разных системах. Проект OOM развивался в этом направлении. В ядре версии 2.6 убийца OOM проходит через список всех процессов и вычисляет предполагаемое значение испорченной памяти. Процесс, который имеет максимальное значение испорченной памяти, убивается.

OOM это последняя попытка системы, чтобы оправиться от проблемы с недостатком памяти. Разработчик в первую очередь обязан убедиться, что этого не происходит. Ниже приведены два метода, которые могут сделать систему более устойчивой к утечкам памяти:

 

Настройка водяных знаков памяти для каждого процесса: первым шагом в этом направлении является выявление плохих программ, которые вызывают утечки памяти. Это можно сделать, установив ограничении RSS для каждого процесса, работающего в системе, с помощью системного вызова setrlimit(). Есть два системных вызова, предоставляемых для этого ядром Linux: setrlimit() и getrlimit() для установки и получения ограничения ресурсов, соответственно. Каждый ресурс имеет жёсткое и мягкое ограничение, определяемое структурой rlimit (смотрите заголовочный файл sys/resource.h). Мягкое ограничение является значением, которое ядро обеспечивает для соответствующего ресурса. Жёсткое ограничение действует в качестве потолка для мягкого ограничения. Могут иметь место различные виды ресурсных ограничений; наиболее значимое, связанное с памятью, это RLIMIT_RSS, которое ограничивает количество страниц, принадлежащих резиденту процесса в оперативной памяти. (Для его использования обратитесь к главной странице setrlimit.)

Отключение чрезмерного выделения памяти (over-commit) в системе: чрезмерное выделение памяти представляет собой ипотечную схему выделения памяти, при которой ядро отводит приложению большое количество динамической памяти, даже если оно не располагает достаточными ресурсами памяти. За превышением ресурсов стоит идея, заключающаяся в том, что обычно приложения для настольных компьютеров выделяют много памяти, но редко используют большую её часть. Следовательно, ядро выполняет выделение памяти, не заботясь о проверке, имеет ли оно такие ресурсы. (Всегда, поскольку из-за подкачки по запросу фактическая память не выделяется, если она не используется.) На встроенных системах рекомендуется выключить эту функцию по двум причинам:
– Вы не должны иметь никаких приложений, желающих выделять огромное количество памяти, а затем использовать её только частично. Такие приложения небрежно обращаются с памятью и не оптимизированы для встроенных систем. (Если приложение небрежно относится к выделению памяти, оно также может быть небрежным и при освобождении памяти.)
– Лучше потерпеть неудачу, когда приложение запрашивает память и памяти не хватает, чем позволить произойти выделению памяти, а затем позже вызвать состояние нехватки памяти при обращении к памяти. Первое проще для отладки и может быть исправлено более легко. Linux предлагает пользователю отключать чрезмерное выделение памяти с помощью proc файла /proc/sys/vm/overcommit. Запись 0 в этот файл отключает чрезмерное выделение памяти.

 

Тем не менее, в случае если вы попали в состояние OOM, и вы уверены, что какое-то приложение вызывает утечку памяти, лучшим решением является использование отладчиков памяти, которые направлены на обнаружение утечек.

 

Предыдущая  Содержание  Следующая