2016-09-28 4 views
5

Я пытаюсь использовать setrlimit, чтобы ограничить использование моей памяти в системе Linux, чтобы остановить мой процесс от сбоя машины (мой код разбивал узлы на высокопроизводительном кластере, потому что ошибка привела к потреблению памяти более 100 гигабайт). Кажется, я не могу найти правильный ресурс, чтобы перейти к setrlimit; Я думаю, что он должен быть резидентом, который cannot be limited with setrlimit, но меня смущает резидент, куча, стек. В приведенном ниже коде; если я раскомментирую только RLIMIT_AS, код не с MemoryError по адресу numpy.ones(shape=(1000, 1000, 10), dtype="f8"), хотя этот массив должен быть всего 80 МБ. Если я раскомментирую только RLIMIT_DATA, RLIMIT_RSS, или RLIMIT_STACK, оба массива получат выделение успешно, даже если общий объем использования памяти составляет 2 ГБ или вдвое больше желаемого.Как использовать `setrlimit` для ограничения использования памяти? RLIMIT_AS убивает слишком рано; RLIMIT_DATA, RLIMIT_RSS, RLIMIT_STACK вообще не убить

Я хотел бы сделать свою программу неудачной (независимо от того, как), как только она попытается выделить слишком много ОЗУ. Почему ни один из RLIMIT_DATA, RLIMIT_RSS, RLIMIT_STACK и RLIMIT_AS делать то, что я имею в виду, и каков правильный ресурс для перехода на setrlimit?

$ cat mwe.py 
#!/usr/bin/env python3.5 

import resource 
import numpy 

#rsrc = resource.RLIMIT_AS 
#rsrc = resource.RLIMIT_DATA 
#rsrc = resource.RLIMIT_RSS 
#rsrc = resource.RLIMIT_STACK 

soft, hard = resource.getrlimit(rsrc) 
print("Limit starts as:", soft, hard) 

resource.setrlimit(rsrc, (1e9, 1e9)) 

soft, hard = resource.getrlimit(rsrc) 
print("Limit is now:", soft, hard) 
print("Allocating 80 KB, should certainly work") 
M1 = numpy.arange(100*100, dtype="u8") 

print("Allocating 80 MB, should work") 
M2 = numpy.arange(1000*1000*10, dtype="u8") 

print("Allocating 2 GB, should fail") 
M3 = numpy.arange(1000*1000*250, dtype="u8") 

input("Still here…") 

Выход с RLIMIT_AS линии раскомментировал:

$ ./mwe.py 
Limit starts as: -1 -1 
Limit is now: 1000000000 -1 
Allocating 80 KB, should certainly work 
Allocating 80 MB, should work 
Traceback (most recent call last): 
    File "./mwe.py", line 22, in <module> 
    M2 = numpy.arange(1000*1000*10, dtype="u8") 
MemoryError 

Вывод при работе с любым из остальных незакомментированной:

$ ./mwe.py 
Limit starts as: -1 -1 
Limit is now: 1000000000 -1 
Allocating 80 KB, should certainly work 
Allocating 80 MB, should work 
Allocating 2 GB, should fail 
Still here… 

В последней строке, top сообщает, что мой процесс используя 379 ГБ VIRT, 2,0 ГБ ВИЭ.


Системные детали:

$ uname -a 
Linux host.somewhere.ac.uk 2.6.32-573.3.1.el6.x86_64 #1 SMP Mon Aug 10 09:44:54 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux 

$ cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 6.7 (Santiago) 

$ free -h 
      total  used  free  shared buffers  cached 
Mem:   2.0T  1.9T  37G  1.6G  3.4G  1.8T 
-/+ buffers/cache:  88G  1.9T 
Swap:   464G  4.8M  464G 

$ python3.5 --version 
Python 3.5.0 

$ python3.5 -c "import numpy; print(numpy.__version__)" 
1.11.1 
+0

Возможный дубликат [Настройка STACKSIZE в питон скрипт] (https://stackoverflow.com/questions/5061582/setting-stacksize-in-a-python-script) – jww

+0

Попытка установить 'rlimit_stack' после [ Stack Clash] (http://www.openwall.com/lists/oss-security/2017/06/19/1) исправления могут привести к сбою или смежным проблемам. Также см. Red Hat [выпуск 1463241] (https://bugzilla.redhat.com/show_bug.cgi?id=1463241) – jww

ответ

1

Увы у меня нет ответа на ваш вопрос. Но я надеюсь, что следующее может помочь:

  • Ваш скрипт работает как ожидается в моей системе. Пожалуйста, поделитесь точной спецификацией для вашей, может быть, есть известная проблема с Linux-дистрибутивом, ядром или даже numpy ...
  • Вы должны быть в порядке с RLIMIT_AS. Как объясняется here, это должно ограничивать всю виртуальную память, используемую процессом. И виртуальная память включает в себя все: swap-память, разделяемые библиотеки, код и данные. Подробнее here.
  • Вы можете добавить следующую функцию (принятую от this answer) в скрипт для проверки фактического использования виртуальной памяти в любой момент:

    def peak_virtual_memory_mb(): 
        with open('/proc/self/status') as f: 
         status = f.readlines() 
         vmpeak = next(s for s in status if s.startswith("VmPeak:")) 
         return vmpeak 
    
  • А общий совет, отключить память подкачки. По моему опыту с высокопроизводительными серверами это приносит больше вреда, чем решает проблемы.
+0

Я добавил некоторые детали системы. Нужно ли добавлять еще? 'top' сообщает, что я использую 379 ГБ виртуальной памяти.Я не знаю почему, но это, вероятно, объясняет, почему версия RLIMIT_AS не работает раньше. NB: Я просто пользователь на этом сервере и не могу отключить память подкачки. – gerrit

+0

Да, действительно, 379GB действительно странно, и это может объяснить ранний провал. Какая версия Linux работает на машине? Вы пытались «печатать peak_virtual_memory_mb()' до и после выделения памяти? BTW, возможно, лучше не разделить имя хоста на общедоступном сайте :) –

+0

@ Это Redhat Enterprise Linux (см. Править). Я не уверен, как печатать пиковую виртуальную память. – gerrit