Вид Unix из памяти

Предположения:

  • Все Ваши экземпляры сценария работают на той же машине.
  • Существует известный каталог, где Ваш сценарий может записать, и что никакая другая программа не будет использовать. Этот каталог находится в “обычной” файловой системе (в частности, не NFS).

Можно использовать атомарные операции, такие как создание файла (set -C; (: >foo) 2>/dev/null), переименование (mv) и удаление (rm) обработать блокировку.

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

Во-первых, настройте каталог. Создайте названный файл lock и названный именованный канал pipe.

if ! [ -d /script-locking-directory ]; then
  # The directory doesn't exist, create and populate it
  {
    mkdir /script-locking-directory-$$ &&
    mkfifo /script-locking-directory-$$/pipe &&
    touch /script-locking-directory-$$/lock &&
    mv /script-locking-directory-$$ /script-locking-directory
  } || {
    # An error happened, so clean up
    err=$?
    rm -r /script-locking-directory-$$
    # Exit, unless another instance of the script created the directory
    # at the same time as us
    if ! [ -d /script-locking-directory ]; then exit $?; fi
  }
fi

Мы реализуем взятие блокировки путем переименования lock файл. Кроме того, мы будем использовать простой план уведомить всех официантов относительно блокировки: повторите байт к каналу и имейте всех официантов, ожидают путем чтения из того канала. Вот простая схема.

take_lock () {
  while ! mv lock lock.held 2>/dev/null; do
    read <pipe # wait for a write on the pipe
  done
}
release_lock () {
  mv lock.held lock
  read <pipe & # make sure there is a reader on the pipe so we don't block
  echo >pipe # notify all readers
}

Эта схема будит всех официантов, которые могут быть неэффективными, но это не будет проблемой, если не будет много конкуренции (т.е. много официантов одновременно).

Основная проблема с кодом выше состоит в том, что, если держатель блокировки умирает, блокировка не будет выпущена. Как мы можем обнаружить ту ситуацию? Мы не можем только пойти, ища процесс, названный как блокировка из-за повторного использования PID. То, что мы можем сделать, открыть файл блокировки в сценарии и проверку, если файл блокировки открыт, когда новый экземпляр сценария запускается.

break_lock () {
  if ! [ -e "lock.held" ]; then return 1; fi
  if [ -n "$(fuser lock.held)" ]; then return 1; fi
  # If we get this far, the lock holder died
  if mv lock.held lock.breaking.$$ 2>/dev/null; then
    # Check that someone else didn't break the lock and take it just now
    if [ -n "$(fuser lock.breaking.$$)" ]; then
      mv lock.breaking.$$ lock.held
      return 0
    fi
    mv lock.breaking.$$ lock
  fi
  return 0 # whether we did break a lock or not, try taking it again
}
take_lock () {
  while ! mv lock lock.taking.$$ 2>/dev/null; do
    if break_lock; then continue; fi
    read <pipe # wait for a write on the pipe
  done
  exec 9<lock.taking.$$
  mv lock.taking.$$ lock.held
}
release_lock () {
  # lock.held might not exist if someone else is trying to break our lock.
  # So we try in a loop.
  while ! mv lock.held lock.releasing.$$ 2>/dev/null; do :; done
  exec 9<&-
  mv lock.releasing.$$ lock
  read <pipe & # make sure there is a reader on the pipe so we don't block
  echo >pipe # notify all readers
}

Эта реализация может все еще зайти в тупик, если держатель блокировки умирает, в то время как другой экземпляр внутри take_lock: блокировка останется сохраненной, пока третий экземпляр не запустится. Я также предполагаю, что сценарий не умрет внутри take_lock или release_lock.

Предупреждение: Я написал код выше непосредственно в браузере, я не протестировал его (уже не говоря о доказанном, который он исправляет).

7
19.03.2013, 01:27
3 ответа

Не использовать -S 10G, это слишком много (и вероятно не выполнение, что Вы думаете). Запуск OOMkiller действительно означает, что Ваша система использует весь, его - память.

Согласно алгоритму, используемому sort, это будет использовать память согласно тому, что доступно: половина самого большого количества между TotalMem/8 и AvailableMem.

Так, например, если у Вас есть 4 ГБ доступной мадам (из 8 ГБ), sort будет использовать 2 ГБ RAM. Это должно также создать много файлов на 2 ГБ в/bigdisk и наконец сортировать их с объединением.

3
27.01.2020, 20:19
  • 1
    Честно говоря, вид уничтожен, если я использую-S или нет. И вершина и/proc/meminfo сообщают, что у меня есть свободная память на смерти. Машина имеет 16G поршня, и только 3 на самом деле используются, когда процесс вида запускается. Вручную использующее разделение, вид на частях и них вид-m работали без проблем памяти. –  Aiden Bell 19.03.2013, 01:25
  • 2
    @AidenBell я просто думал о чем-то: Вы используете версию на 32 бита sort? Свериться file $(which sort). –  Totor 19.03.2013, 02:07
  • 3
    нет. 64-разрядный. Я начинаю думать, что это могла бы быть фактическая ошибка удушья где-нибудь. –  Aiden Bell 19.03.2013, 20:29

Установка Try vm.overcommit_memory = 1: «…

Когда этот флаг равняется 1, ядро притворяется, что всегда существует достаточно памяти, пока это на самом деле не заканчивается.

…»

И действительно используйте подкачку.

0
27.01.2020, 20:19
  • 1
    Уничтожитель OOM только инициирован, когда "он на самом деле заканчивается" памяти. Так это настройки ничего не решат. Это могло бы иметь, если Из сообщения мадам прибыл из sort а не от ядра. –  Totor 16.03.2013, 20:12
  • 2
    Прочитайте руководство: „… уничтожитель OOM может быть полностью отключен со следующей командой. Это не рекомендуется для продуктивных сред, потому что, если условие из памяти действительно представляет себя, могло бы быть неожиданное поведение в зависимости от доступных системных ресурсов и конфигурации. … что-либо от ядра паникуют к подвешиванию в зависимости от ресурсов, доступных ядру во время условия OOM. sysctl vm.overcommit_memory=2 повторяют "vm.overcommit_memory=2">>/etc/sysctl.conf …” - — oracle.com/technetwork/articles/servers-storage-dev / Очень хороший –  poige 05.05.2015, 14:33
  • 3
    мне не удается видеть уместность Вашего комментария. Отключение OOM-уничтожителя не решит проблему, которая является: sort использование/потребности слишком много памяти. С overcommit_memory=2, sort просто не malloc() и очень, вероятно, не отсортирует, затем. It –  Totor 06.05.2015, 02:19
  • 4
    не был =2. Это был процитировать показ, что настройки этой опции имеют прямое отношение к OOM-уничтожению. Если бы Вы хотите знать предмет лучше, ну, в общем, хорошо, который удовлетворил бы Вашей цели (надо надеяться): огромное спасибо lwn.net/Articles/317814 –  poige 06.05.2015, 05:11

Создание ответа от моего комментария:

У меня была такая же проблема, когда я использовал / Run / Shm , как мой / BigDisk для хранения Сортировка TEMP файлов. / RUN / SHM - это RAM-диск, поэтому, когда сортировка необходима для кэширования частичных результатов на диске (который он делает, когда память почти заполнена), память выбежала. Убил ядро ​​ сортировка , так как это был процесс, используя наибольшую память.

Использование местоположения, хранящегося на физическом диске вместо RAM-диска, решила его.

1
27.01.2020, 20:19

Теги

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