Подпроцесс Python.Popen «OSError: [Errno 12] Cannot allocate memory»

114

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

Сценарий python запускает набор функций класса каждые 60 секунд с использованием модуля sched :

# sc is a sched.scheduler instance
sc.enter(60, 1, self.doChecks, (sc, False))

Сценарий выполняется как демонизированный процесс с использованием приведенного здесь кода .

Ряд методов класса, которые вызываются как часть doChecks, используют модуль subprocess для вызова системных функций с целью получения системной статистики:

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]

Это работает нормально в течение определенного периода времени, прежде чем весь скрипт выйдет из строя со следующей ошибкой:

File "/home/admin/sd-agent/checks.py", line 436, in getProcesses
File "/usr/lib/python2.4/subprocess.py", line 533, in __init__
File "/usr/lib/python2.4/subprocess.py", line 835, in _get_handles
OSError: [Errno 12] Cannot allocate memory

Результат команды free -m на сервере после сбоя сценария:

$ free -m
                  total       used       free     shared     buffers    cached
Mem:                894        345        549          0          0          0
-/+ buffers/cache:  345        549
Swap:                 0          0          0

На сервере работает CentOS 5.3. Я не могу воспроизвести на своих ящиках CentOS или с другими пользователями, сообщающими о той же проблеме.

Я пробовал несколько вещей, чтобы отладить это, как было предложено в исходном вопросе:

  1. Регистрация вывода команды free -m до и после вызова Popen. Нет значительных изменений в использовании памяти, т.е. память не используется постепенно по мере выполнения сценария.

  2. Я добавил close_fds = True к вызову Popen, но это не имело значения - скрипт по-прежнему вылетал с той же ошибкой. Предлагается здесь и здесь .

  3. Я проверил rlimits, которые показали (-1, -1) как для RLIMIT_DATA, так и для RLIMIT_AS, как предлагается здесь .

  4. Статья предложила, не имеющее пространство подкачки не может быть причиной , но замена на самом деле предоставляется по запросу ( в зависимости от веба - хостинга) , и это также было предложено в качестве поддельных привести здесь .

  5. Процессы закрываются, потому что это поведение использования .communicate (), которое поддерживается исходным кодом Python и комментариями здесь .

Все проверки можно найти на GitHub здесь с функцией getProcesses, определенной в строке 442. Она вызывается doChecks (), начиная со строки 520.

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

recv(4, "Total Accesses: 516662\nTotal kBy"..., 234, 0) = 234
gettimeofday({1250893252, 887805}, NULL) = 0
write(3, "2009-08-21 17:20:52,887 - checks"..., 91) = 91
gettimeofday({1250893252, 888362}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 74) = 74
gettimeofday({1250893252, 888897}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 67) = 67
gettimeofday({1250893252, 889184}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 81) = 81
close(4)                                = 0
gettimeofday({1250893252, 889591}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 63) = 63
pipe([4, 5])                            = 0
pipe([6, 7])                            = 0
fcntl64(7, F_GETFD)                     = 0
fcntl64(7, F_SETFD, FD_CLOEXEC)         = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)
write(2, "Traceback (most recent call last"..., 35) = 35
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 52) = 52
open("/home/admin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/home/admin/sd-agent/dae"..., 60) = 60
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 54) = 54
open("/usr/lib/python2.4/sched.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/sched"..., 55) = 55
fstat64(8, {st_mode=S_IFREG|0644, st_size=4054, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "\"\"\"A generally useful event sche"..., 4096) = 4054
write(2, "    ", 4)                     = 4
write(2, "void = action(*argument)\n", 25) = 25
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 60) = 60
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 64) = 64
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 65) = 65
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "errread, errwrite)\n", 19)    = 19
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 71) = 71
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
read(8, "table(self, handle):\n           "..., 4096) = 4096
read(8, "rrno using _sys_errlist (or siml"..., 4096) = 4096
read(8, " p2cwrite = None, None\n         "..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "self.pid = os.fork()\n", 21)  = 21
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
write(2, "OSError", 7)                  = 7
write(2, ": ", 2)                       = 2
write(2, "[Errno 12] Cannot allocate memor"..., 33) = 33
write(2, "\n", 1)                       = 1
unlink("/var/run/sd-agent.pid")         = 0
close(3)                                = 0
munmap(0xb7e0d000, 4096)                = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x589978}, {0xb89a60, [], SA_RESTORER, 0x589978}, 8) = 0
brk(0xa022000)                          = 0xa022000
exit_group(1)                           = ?
Дэвидмиттон
источник
1
исчерпание «каналов», файловых дескрипторов или связанных с ними ресурсов ядра?
Blauohr 02
Проверить /var/log/messages, или dmesgкомандовать.
mark4o 02
В журнале нет ничего относящегося к этому.
Дэвидмиттон
Вы когда-нибудь находили решение этой проблемы? У меня очень похожие симптомы. У меня много свободной памяти, но после добавления подкачки (как подсказывают некоторые из ваших ответов) проблема исчезнет. Просто интересно, узнали ли вы что-нибудь за прошедшие месяцы с тех пор и сейчас. -- Спасибо!
dpb
Я столкнулся с той же проблемой, но без решения - есть идеи?

Ответы:

89

По общему правилу (т.е. в ваниль семечек), fork/ cloneсбои с ENOMEM происходят конкретно из - либо честный к Богу вне памяти состояния ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, и mm_initт.д. каркать), или потому , что security_vm_enough_memory_mmне удалось вам , а исполнение в overcommit политику .

Начните с проверки vmsize процесса, который не удалось выполнить вилку, во время попытки вилки, а затем сравните ее с объемом свободной памяти (физической и подкачки), поскольку он связан с политикой переопределения (введите числа).

В вашем конкретном случае обратите внимание, что ПК-Р-Виртуализация имеет дополнительные проверки при принудительном превышении лимита . Более того, я не уверен, насколько у вас действительно есть контроль изнутри вашего контейнера над конфигурацией swap и overcommit (для того, чтобы повлиять на результат принудительного исполнения).

Теперь, чтобы действительно двигаться вперед, я бы сказал, что у вас осталось два варианта :

  • переключиться на более крупный экземпляр или
  • поставить некоторые работы по кодированию в более эффективном контроле памяти вашего скрипта следа

ОБРАТИТЕ ВНИМАНИЕ, что усилия по кодированию могут оказаться напрасными, если окажется, что это не вы, а какой-то другой парень, размещенный в другом экземпляре на том же сервере, что и вы, запущенный из-под контроля.

Что subprocess.Popenкасаетсяforkclone памяти, мы уже знаем, что он использует / под капотом , что означает, что каждый раз, когда вы вызываете его, вы запрашиваете еще раз столько памяти, сколько Python уже съедает , то есть в сотнях дополнительных МБ, и все для того, чтобы затем execкрошечный исполняемый файл размером 10 КБ, такой как freeили ps. В случае невыгодной политики чрезмерных ограничений вы скоро увидите ENOMEM.

Альтернативы тому, forkчто не имеют этой таблицы родительских страниц и т. Д., Проблема копирования есть vforkи posix_spawn. Но если вам не хочется переписывать фрагменты subprocess.Popenв терминах vfork/ posix_spawn, рассмотрите возможность использования suprocess.Popenтолько один раз, в начале вашего скрипта (когда объем памяти Python минимален), чтобы создать скрипт оболочки, который затем запускает free/ ps/ sleepи все остальное в цикл параллельно вашему скрипту; опрашивать вывод скрипта или читать его синхронно, возможно, из отдельного потока, если у вас есть другие вещи, которые нужно позаботиться асинхронно - обработайте ваши данные в Python, но оставьте разветвление подчиненному процессу.

ОДНАКО , в вашем конкретном случае вы можете пропустить вызов psи freeвообще; эта информация легко доступна вам в Python напрямуюprocfs , независимо от того, хотите ли вы получить к ней доступ самостоятельно или через существующие библиотеки и / или пакеты . Если бы psи freeбыли единственными утилитами, которые вы использовали, то вы можете полностью отказаться от нихsubprocess.Popen .

Наконец, что бы вы ни делали subprocess.Popen, если ваш скрипт утекает память, вы все равно в конечном итоге столкнетесь с проблемой. Следите за ним и проверяйте наличие утечек памяти .

владр
источник
8
Я обнаружил, что запуск gc.collect()непосредственно перед запуском subprocess.Popenпомогает в тех случаях, когда сборщик мусора некоторое время не запускался.
letmaik 02
Я написал демон для обработки стратегии вспомогательного скрипта: github.com/SeanHayes/errand-boy Я использую его в продакшене с одним из моих клиентов, и наши проблемы «Невозможно выделить память» исчезли.
Шон Хейс
Я был бы признателен за простую диагностику, например, следующее, /proc/fd/mapsчтобы определить, действительно ли проблема
связана с перегрузкой
18

Глядя на результат, free -mмне кажется, что на самом деле у вас нет доступной памяти подкачки. Я не уверен, что в Linux своп всегда будет доступен автоматически по запросу, но у меня была та же проблема, и ни один из ответов здесь мне не помог. Однако добавление некоторой памяти подкачки устранило проблему в моем случае, поэтому, поскольку это может помочь другим людям, столкнувшимся с той же проблемой, я публикую свой ответ о том, как добавить подкачку 1 ГБ (в Ubuntu 12.04, но он должен работать аналогично для других дистрибутивов).

Сначала вы можете проверить, включена ли какая-либо память подкачки.

$sudo swapon -s

если он пуст, это означает, что у вас не включен обмен. Чтобы добавить своп размером 1 ГБ:

$sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
$sudo mkswap /swapfile
$sudo swapon /swapfile

Добавьте следующую строку в, fstabчтобы сделать обмен постоянным.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

Источник и дополнительную информацию можно найти здесь .

Нима
источник
1
Это устранило ту же проблему или другую?
Дима Тиснек
Это помогло мне в CentOS 6.4. Столкнулся с ошибкой при установке awstats, спасибо.
Руслан Абузант 07
Хотя это позволило мне выполнить код, на самом деле это не решило проблему, которая, вероятно, кроется в библиотеке, которую я использую.
philmaweb
1
Вы устранили мою проблему. Спасибо! +1
sscirrus 08
8

своп не может быть отвлекающим маневром, предложенным ранее. Насколько велик рассматриваемый процесс python непосредственно перед ENOMEM?

В ядре 2.6 /proc/sys/vm/swappinessконтролирует, насколько активно ядро ​​будет переключаться на подкачку, и overcommit*сколько файлов и насколько точно ядро ​​может распределять память, подмигивая и кивая. Как и ваш статус отношений в Facebook, это сложно .

... но своп фактически доступен по запросу (согласно веб-хосту) ...

но не в соответствии с выводом вашей free(1)команды, который показывает, что пространство подкачки не распознается вашим экземпляром сервера. Ваш веб-хост, безусловно, может знать об этой теме гораздо больше, чем я, но виртуальные системы RHEL / CentOS, которые я использовал, сообщали о подкачке, доступной для гостевой ОС.

Адаптация статьи 15252 Red Hat KB :

Система Red Hat Enterprise Linux 5 будет работать нормально без пространства подкачки, если сумма анонимной памяти и общей памяти системы V составляет менее 3/4 объема ОЗУ. .... В системах с оперативной памятью 4 ГБ или меньше [рекомендуется] не менее 2 ГБ пространства подкачки.

Сравните ваши /proc/sys/vmнастройки с простой установкой CentOS 5.3. Добавьте файл подкачки. Попробуй swappinessи посмотри, живешь ли ты дольше.

знак абзаца
источник
Как лучше всего проверить размер процесса Python? пс?
Дэвидмиттон, 03
что-то вроде ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PID, или top (1), должно это сделать.
pilcrow
7

Для простого исправления вы можете

echo 1 > /proc/sys/vm/overcommit_memory

если вы уверены, что в вашей системе достаточно памяти. См. Linux по эвристике фиксации .

Serv-вкл
источник
1
Спасибо вам большое! Такое простое решение, вы спасли мне день)
igolkotek
5

Я продолжаю подозревать, что у вашего клиента / пользователя загружен какой-то модуль ядра или драйвер, который мешает clone()системному вызову (возможно, какое-то неясное улучшение безопасности, что-то вроде LIDS, но более неясное?) Или каким-то образом заполняет некоторые структуры данных ядра, которые необходимы для fork()/ clone()для работы (таблица процессов, таблицы страниц, таблицы дескрипторов файлов и т. д.).

Вот соответствующая часть fork(2)справочной страницы:

ОШИБКИ
       EAGAIN fork () не может выделить достаточно памяти для копирования родительских таблиц страниц и выделения структуры задачи для
              ребенок.

       EAGAIN Невозможно создать новый процесс, поскольку обнаружен предел ресурса RLIMIT_NPROC вызывающего объекта. Чтобы
              превышает этот предел, процесс должен иметь возможность CAP_SYS_ADMIN или CAP_SYS_RESOURCE.

       ENOMEM fork () не удалось выделить необходимые структуры ядра из-за нехватки памяти.

Я предлагаю пользователю попробовать это после загрузки стандартного общего ядра и с минимальным набором модулей и загруженных драйверов (минимально необходимым для запуска вашего приложения / скрипта). Оттуда, если он работает в этой конфигурации, они могут выполнить бинарный поиск между этой конфигурацией и конфигурацией, в которой обнаружена проблема. Это стандартное решение 101 для устранения неполадок системного администратора.

Соответствующая строка в вашем strace:

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)

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

Однако я подозреваю, что это все еще отвлекающий маневр.

Тот факт, что freeкэш и буферы использует 0 (НОЛЬ) памяти, очень тревожат. Я подозреваю, что freeвывод ... и, возможно, проблема с вашим приложением здесь вызваны каким-то проприетарным модулем ядра, который каким-то образом мешает распределению памяти.

Согласно страницам руководства для fork () / clone () системный вызов fork () должен возвращать EAGAIN, если ваш вызов вызовет нарушение ограничения ресурсов (RLIMIT_NPROC) ... однако он не говорит, должен ли возвращаться EAGAIN другими нарушениями RLIMIT *. В любом случае, если ваша цель / хост имеет какие-то странные параметры Vormetric или другие параметры безопасности (или даже если ваш процесс работает под какой-то странной политикой SELinux), это может вызвать сбой -ENOMEM.

Маловероятно, что это будет обычная проблема Linux / UNIX. У вас там происходит что-то нестандартное.

Джим Деннис
источник
1
Сервер работает на базе шаблона мультимедиа (dv), который использует ПК Р-Виртуализация для виртуализации.
Дэвидмиттон
Попробуйте поискать в досках сообщений и системе отслеживания ошибок ПК Р-Виртуализация и, возможно, поискать обновления самой подсистемы ПК Р-Виртуализация.
Джим Деннис
2

Вы пробовали использовать:

(status,output) = commands.getstatusoutput("ps aux")

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

После некоторого тестирования я обнаружил, что это происходило только в более старых версиях python: это происходит с 2.6.5, но не с 2.7.2.

Мой поиск привел меня сюда python-close_fds-issue , но отключение closed_fds не решило проблему. Это все еще стоит прочитать.

Я обнаружил, что в Python произошла утечка файловых дескрипторов, просто следя за ним:

watch "ls /proc/$PYTHONPID/fd | wc -l"

Как и вы, я хочу зафиксировать вывод команды, и я хочу избежать ошибок OOM ... но похоже, что единственный способ для людей - использовать менее глючную версию Python. Не идеально ...

Totaam
источник
0

munmap (0xb7d28000, 4096) = 0
запись (2, «OSError», 7) = 7

Я видел неряшливый код, который выглядит так:

serrno = errno;
some_Syscall(...)
if (serrno != errno)
/* sound alarm: CATROSTOPHIC ERROR !!! */

Вы должны проверить, происходит ли это в коде Python. Errno допустимо только в случае сбоя системного вызова.

Отредактировано для добавления:

Вы не говорите, сколько длится этот процесс. Возможные потребители памяти

  • разветвленные процессы
  • неиспользуемые структуры данных
  • общие библиотеки
  • файлы с отображением памяти
codeDr
источник
2
Да, но мы видим из strace OP, что первый сбой системного вызова - от clone () - это ENOMEM, как сообщается. Эта ошибка сохраняется во время спотыкания Python о нехватке памяти при построении трассировки, даже несмотря на то, что C-библиотека errnoсбрасывается много раз в процессе.
pilcrow