Как ограничить размер кучи?

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

Из-за этого я хочу ограничить объем памяти, которую может увеличить куча Python. Когда предел достигнут, программа может просто аварийно завершить работу. Какой лучший способ сделать это?

Если это имеет значение, большая часть кода написана на Cython, поэтому она должна учитывать выделенную там память. Я не женат на чистом Python-решении (оно не должно быть переносимым), поэтому все, что работает в Linux, подойдет.

3 ответа

Решение

Проверьте resource.setrlimit (). Он работает только в системах Unix, но, похоже, это то, что вам нужно, поскольку вы можете выбрать максимальный размер кучи для вашего процесса и его дочерних элементов с помощью параметра resource.RLIMIT_DATA.

РЕДАКТИРОВАТЬ: Добавление примера:

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. Я не уверен, реализован ли sigaltstack в python, так что это может оказаться затруднительным, если вы хотите восстановиться после перехода через эту границу.

Посмотрите на ulimit. Это позволяет устанавливать квоты ресурсов. Также могут потребоваться соответствующие настройки ядра.

Следующий код выделяет память для указанного максимального размера резидентного набора

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.

Другие вопросы по тегам