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

Я запускаю pdftoppm, чтобы преобразовать предоставленный пользователем PDF в изображение 300DPI. Это отлично работает, за исключением случаев, когда пользователь предоставляет PDF с очень большим размером страницы. pdftoppm выделяет достаточно памяти для хранения изображения 300DPI такого размера в памяти, что для 100-дюймовой квадратной страницы составляет 100 * 300 * 100 * 300 * 4 байта на пиксель = 3,5 ГБ. Злоумышленник может просто дать мне глупый PDF-файл и вызвать всевозможные проблемы.

Итак, что бы я хотел сделать, это установить какой-то жесткий лимит на использование памяти для дочернего процесса, который я собираюсь запустить - просто запустите процесс, если он попытается выделить больше, чем, скажем, 500 МБ Память. Возможно ли это?

Я не думаю, что для этого можно использовать ulimit, но есть ли однопроцессный эквивалент?

129 голосов | спросил Ben Dilts 13 FebruaryEurope/MoscowbSun, 13 Feb 2011 11:00:34 +0300000000amSun, 13 Feb 2011 11:00:34 +030011 2011, 11:00:34

5 ответов


50

Есть проблемы с ulimit. Вот полезное чтение по теме: Ограничение времени и памяти для программы в Linux , что приводит к тайм-ауту , что позволяет вы привязываете процесс (и его вилки) по времени или потреблению памяти.

Для тайм-аута требуется установить Perl 5+ и файловую систему /proc. После этого вы копируете инструмент, например. /usr/local/bin:

curl https://raw.githubusercontent.com/pshved/timeout/master/timeout \
  sudo tee /usr/local/bin/timeout && sudo chmod 755 /usr/local/bin/timeout

После этого вы можете «привязать» свой процесс к потреблению памяти, как в своем вопросе, например:

timeout -m 500 pdftoppm Sample.pdf

В качестве альтернативы вы можете использовать -t <seconds> и -x <hertz>, чтобы соответственно ограничить процесс по времени или ограничениям на cpu.

Как работает этот инструмент, проверяя несколько раз в секунду, если порожденный процесс не превысил установленные границы. Это означает, что на самом деле есть небольшое окно, в котором процесс мог бы потенциально переподписываться перед уведомлениями о тайм-ауте и убивает процесс.

Более правильный подход, скорее всего, будет связан с группами, но это гораздо более важно для настройки, даже если вы будете использовать Docker или runC, которые, среди прочего, предлагают более удобную абстракцию вокруг групп.

ответил kvz 30 32011vEurope/Moscow11bEurope/MoscowWed, 30 Nov 2011 13:42:33 +0400 2011, 13:42:33
89

Другой способ ограничить это - использовать контрольные группы Linux. Это особенно полезно, если вы хотите ограничить выделение (или группу процессов) процесса физической памятью из виртуальной памяти. Например:

cgcreate -g memory:/myGroup
echo $(( 500 * 1024 * 1024 )) > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes
echo $(( 5000 * 1024 * 1024 )) > /sys/fs/cgroup/memory/myGroup/memory.memsw.limit_in_bytes

создаст контрольную группу с именем myGroup, закроет набор процессов, выполняемых под myGroup, до 500 МБ физической памяти и до 5000 Мбайт свопа. Чтобы запустить процесс в группе управления:

cgexec -g memory:myGroup pdftoppm

Обратите внимание, что в современном дистрибутиве Ubuntu этот пример требует установки пакета cgroup-bin и редактирования /etc/default/grub для изменения GRUB_CMDLINE_LINUX_DEFAULT to:

GRUB_CMDLINE_LINUX_DEFAULT="cgroup_enable=memory swapaccount=1"

, а затем запустите sudo update-grub и перезагрузитесь для загрузки с новыми параметрами загрузки ядра.

ответил user65369 16 PMpWed, 16 Apr 2014 12:36:40 +040036Wednesday 2014, 12:36:40
64

Если ваш процесс не порождает больше детей, которые потребляют большую часть памяти, вы можете использовать setrlimit . Более общий пользовательский интерфейс для этого заключается в использовании команды ulimit оболочки:

$ ulimit -Sv 500000     # Set ~500 mb limit
$ pdftoppm ...

Это ограничит только «виртуальную» память вашего процесса, принимая во внимание «и ограничивая» память, в которой процесс, вызываемый совместно с другими процессами, и память, отображаемая, но не зарезервированная (например, большая куча Java) , Тем не менее, виртуальная память является ближайшим приближением для процессов, которые растут очень большими, делая указанные ошибки несущественными.

Если ваша программа порождает детей, а именно они выделяют память, она становится более сложной, и вы должны писать вспомогательные скрипты для запуска процессов под вашим контролем. Я написал в своем блоге почему и как .

ответил P Shved 13 FebruaryEurope/MoscowbSun, 13 Feb 2011 11:11:37 +0300000000amSun, 13 Feb 2011 11:11:37 +030011 2011, 11:11:37
5

В дополнение к инструментам из daemontools, предложенным Марком Джонсоном, вы также можете рассмотреть chpst, который находится в runit. Сам Runit находится в busybox, поэтому вы, возможно, уже установили его.

В странице руководства chpst показана опция

  

-m байт       ограничить память. Ограничьте сегмент данных, сегмент стека, заблокированные физические страницы и общее количество всего сегмента за процесс до байтов байтов   каждая.

ответил Oz123 9 J000000Thursday15 2015, 15:26:58
5

Я использую приведенный ниже скрипт, который отлично работает. Он использует группы через cgmanager. Обновление: теперь он использует команды из cgroup-tools. Назовите этот скрипт limitmem и поместите его в свой $ PATH, и вы можете использовать его как limitmem. Это ограничит использование памяти и свопа. Чтобы ограничить только память, удалите строку с помощью limitmem 100M bash.

Отказ от ответственности: я не удивлюсь, если memory.memsw.limit_in_bytes также сломается в будущем. Правильным решением было бы использовать systemd api для управления группами, но для этого не требуется никаких средств командной строки.

 cgroup-tools
ответил JanKanis 26 PMpTue, 26 Apr 2016 15:53:52 +030053Tuesday 2016, 15:53:52

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132