Как ограничить размер кучи?
Я иногда пишу программы Python, которые очень трудно определить, сколько памяти он будет использовать перед выполнением. Поэтому я иногда вызываю программу Python, которая пытается выделить огромное количество оперативной памяти, из-за чего ядро сильно меняет местами и ухудшает производительность других запущенных процессов.
Из-за этого я хочу ограничить, сколько памяти куча Python может расти. Когда предел достигнут, программа может просто сработать. Какой лучший способ сделать это?
Если это имеет значение, в Cython написано много кода, поэтому он должен учитывать память, выделенную там. Я не женат на чистом решении Python (его не нужно переносить), поэтому все, что работает в Linux, прекрасно.
Ответы
Ответ 1
Отметьте resource.setrlimit(). Он работает только в системах Unix, но похоже, что это может быть то, что вы ищете, так как вы можете выбрать максимальный размер кучи для вашего процесса и ваших дочерних процессов с параметром resource.RLIMIT_DATA.
EDIT: добавление примера:
import resource
rsrc = resource.RLIMIT_DATA
soft, hard = resource.getrlimit(rsrc)
print 'Soft limit starts as :', soft
resource.setrlimit(rsrc, (1024, hard)) #limit to one kilobyte
soft, hard = resource.getrlimit(rsrc)
print 'Soft limit changed to :', soft
Я не уверен, что ваш вариант использования в точности, но вам может потребоваться установить ограничение на размер стека вместо resouce.RLIMIT_STACK. Пройдя этот предел, вы отправите сигнал SIGSEGV вашему процессу, и для его обработки вам потребуется использовать альтернативный стек сигналов, как описано в файле setrlimit Linux manpage. Я не уверен, что sigaltstack реализован в python, так что это может оказаться трудным, если вы хотите оправиться от перехода по этой границе.
Ответ 2
Посмотрите ulimit. Он позволяет устанавливать квоты ресурсов. Возможно, нужны соответствующие настройки ядра.
Ответ 3
Следующий код выделяет память на указанный максимальный размер резидентного набора
import resource
def set_memory_limit(memory_kilobytes):
# ru_maxrss: peak memory usage (bytes on OS X, kilobytes on Linux)
usage_kilobytes = lambda: resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
rlimit_increment = 1024 * 1024
resource.setrlimit(resource.RLIMIT_DATA, (rlimit_increment, resource.RLIM_INFINITY))
memory_hog = []
while usage_kilobytes() < memory_kilobytes:
try:
for x in range(100):
memory_hog.append('x' * 400)
except MemoryError as err:
rlimit = resource.getrlimit(resource.RLIMIT_DATA)[0] + rlimit_increment
resource.setrlimit(resource.RLIMIT_DATA, (rlimit, resource.RLIM_INFINITY))
set_memory_limit(50 * 1024) # 50 mb
Протестировано на машине linux.