Как решить эту проблему памяти изящно?

10

У меня есть стандартный ноутбук Linux (тестирование Debian) с разделом подкачки.

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

  1. Сядьте перед ноутбуком
  2. Откройте терминал
  3. Тип python, тогдаa = [0]*100000000

Теперь высоки шансы, что у вас не будет достаточно оперативной памяти для обработки этого большого списка. Linux заполнит оперативную память, затем произойдет своп и, через пару минут, OOM killer будет запущен и уничтожит (почти) случайные службы, и, надеюсь, если вы нажмете Ctrl + C в нужное время python, и если терминал все еще был фокус, компьютер снова станет отзывчивым.

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

ulimit -Sv [mem] Я слышу в спину!

Хо Хо! "Используйте cgroupsчерез cgexec!" кто-то говорит в первом ряду!

Да, вы правы: это действительно очень хорошие решения. Но:

  • Они не применяются в масштабе всей системы
  • Пределы установлены для каждого процесса
  • Ограничения статичны, без учета реального объема свободной оперативной памяти (AFAIK)
  • Здесь и там , они говорят , что это на самом деле не является хорошим решением для обеспечения соблюдения жестких ограничений.

Я хотел бы, чтобы ядро ​​говорило: «Вы принадлежите пользователю foo (не root), вы используете много памяти, и у нас закончится память. Извините, чувак ... умри сейчас!»

Или: «Что, черт возьми, вы делаете? Вам нужно x МБ, а доступно только y МБ. Да, SWAP пуст, но вы не собираетесь использовать SWAP для выполнения своей грязной работы, не так ли? Нет, я сказал нет! У тебя нет памяти! Если ты настаиваешь, ты умрешь! "

Сообщество
источник
2
В этой статье уже описан алгоритм, который помогает убийце OOM выбрать правильный процесс. Изменение /proc/sys/vm/overcommit_memoryвлияет на поведение ядра при нехватке памяти.
Джофель
1
Да, но overcommit_memoryспециальный файл использует RAM + SWAP в качестве используемой памяти. Я все еще собираюсь поменяться :)
1
Вам также нужно объяснить, как это не является дубликатом этого: unix.stackexchange.com/questions/34334/…, который противоречит вашим группам WRT и отдельным пользователям. PS. Если вы не хотите менять своп, отключите своп .
Златовласка
1
Я хочу обменяться! Я хочу гибернацию, я хочу, чтобы неиспользованные байты хранились! Но я не хочу, чтобы использованные байты там хранились. Что касается ссылки, то ulimitsэто плохая идея, показанная почти везде, так как это ограничение для каждого процесса ... Я знаю, вы знаете :) О cgroups, это определенно лучше, но не хватает чего-то более общего: я говорю о своем ноутбуке, но я также владеть «расчетным» сервером, которым мы делимся три. Если я буду применять такие ограничения для каждого пользователя, я буду ограничен худшим сценарием, не так ли?
1
cgroups действительно применяются к любому процессу, который вы решите, - поместите все процессы пользователя в отдельную группу, и он должен делать то, что вы хотите.
Петер

Ответы:

4

Кто-то предложил вам услышать cgroups. Ну, попробуйте найти это направление, поскольку оно может предоставить вам:

  • применяется к группе задач, которую вы выбираете (таким образом, не для всей системы, но ни для одного процесса)
  • ограничения установлены для группы
  • пределы статичны
  • они могут установить жесткий лимит на память и / или память + подкачка

Нечто подобное может приблизить вас к вашим целям :

group limited {
  memory {
    memory.limit_in_bytes = 50M;
    memory.memsw.limit_in_bytes = 50M;
  }
}

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

Вот выдержка из документации по памяти cgroup :

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

Гюйгенс
источник
Все еще не совсем то, что я ожидал. Но разница между тем, что я ожидаю, и реальностью часто довольно велика :). В этом случае я хотел быть уверен, что не пропустил ничего подобного overcommit_memoryпеременной ядра. Спасибо вам всем.
0

Я часто сталкиваюсь с той же проблемой. Мой общий рабочий процесс включает в себя тяжелые вычисления в MATLAB. Время от времени я буду случайно пытаться выделить новую переменную, которая превышает объем доступной памяти. Система зависает, и мне обычно приходится сильно перезагружать машину, чтобы вернуться к работе. :П

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

Вдохновленный ответом на этот пост , я написал следующий скрипт (я назвал его watch_memory.sh):

#!/bin/bash

MONITOR=$(free | grep 'buffers/cache:')
MEM_USED=$(echo $MONITOR | awk '{ print $3 }')
MEM_FREE=$(echo $MONITOR | awk '{ print $4 }')

MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) ))

while :; do
    if [ "$MEM_PERC" -gt "95" ]
    then
        kill $1
        echo "$1 killed for using too much memory."
        exit
    fi
    sleep 1

    MONITOR=$(free | grep 'buffers/cache:')
    MEM_USED=$(echo $MONITOR | awk '{ print $3 }')
    MEM_FREE=$(echo $MONITOR | awk '{ print $4 }')
    MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) ))
done

Этот скрипт проверяет каждую секунду процент свободного объема памяти. Когда система заканчивается, ваш pid "козла отпущения" (переданный в качестве аргумента скрипту) будет убит.

Без корректировки приоритета (благородства) сценария потребовалось около 10-20 секунд, чтобы убить козла отпущения, но это все равно работало. Запуск сценария с отрицательным приоритетом привел к немедленному уничтожению после нарушения (в этом примере 11916 - это pid, который я хочу уничтожить, если у меня заканчивается память):

sudo nice -n -5 bash watch_memory.sh 11916
Гордон Бин
источник