web-dev-qa-db-ja.com

Python subprocess.Popen "OSError:[Errno 12]メモリを割り当てることができません"

注:この質問はもともと尋ねられました ここ ですが、実際に受け入れ可能な答えが見つからなかったとしても、報奨金の期限が切れました。元の質問で提供されたすべての詳細を含めて、この質問を再質問しています。

pythonスクリプトは sched モジュールを使用して60秒ごとにクラス関数のセットを実行しています:

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

スクリプトは、コード here を使用してデーモン化されたプロセスとして実行されています。

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. Popen呼び出しの前後にfree -mの出力を記録します。メモリ使用量に大きな変化はありません。つまり、スクリプトの実行中にメモリが徐々に消費されることはありません。

  2. Close_fds = TrueをPopen呼び出しに追加しましたが、違いはありませんでした。スクリプトは同じエラーでクラッシュしました。 here および here を推奨します。

  3. here のように、RLIMIT_DATAとRLIMIT_ASの両方で(-1、-1)を示したrlimitsをチェックしました。

  4. 記事 スワップスペースがないことが原因である可能性が示唆されましたが、スワップは実際にオンデマンドで(Webホストによると)利用可能であり、これも偽の原因として示唆されました here

  5. Pythonソースコードとコメント here 。によってバックアップされた.communicate()を使用する動作であるため、プロセスは閉じられています。

442行目から定義されたgetProcesses関数を使用して、チェック全体を GitHub here で見つけることができます。これは、520行目からdoChecks()によって呼び出されます。

スクリプトは、クラッシュの前に次の出力で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)                           = ?
106
DavidM

free -mの出力を見ると、実際にはスワップメモリ​​が利用できないようです。 Linuxで常にスワップがオンデマンドで自動的に使用可能になるかどうかはわかりませんが、同じ問題が発生しており、ここでの答えはどれも本当に役に立ちませんでした。ただし、いくつかのスワップメモリ​​を追加すると、私の場合の問題が修正されたため、同じ問題に直面している他の人に役立つ可能性があるため、1GBのスワップを追加する方法に関する回答を投稿します(Ubuntu 12.04では、他のディストリビューションでも同様に機能するはずです)。

まず、スワップメモリ​​が有効になっているかどうかを確認できます。

$Sudo swapon -s

空の場合、スワップが有効になっていないことを意味します。 1GBのスワップを追加するには:

$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 

ソースと詳細情報は here にあります。

17
Nima

スワップは、以前に提案されたニシンではありません。 ENOMEMの直前の問題のpythonプロセスはどれくらいですか?

カーネル2.6では、_/proc/sys/vm/swappiness_はカーネルがスワップにどれだけ積極的になるかを制御し、_overcommit*_はカーネルがウィンクとうなずきでメモリを割り当てる量と精度をファイルします。 Facebookの関係ステータスと同様に、 複雑です

...しかし、スワップは実際にオンデマンドで利用可能です(ウェブホストによる)...

ただし、free(1)コマンドの出力によると、サーバーインスタンスによって認識されたスワップスペースは表示されません。今、あなたのウェブホストはこのトピックについて私よりもはるかに知っているかもしれませんが、私が使用した仮想RHEL/CentOSシステムはゲストOSで利用可能なスワップを報告しています。

適応 Red Hat KB Article 15252

Red Hat Enterprise Linux 5システムは、匿名メモリとSystem V共有メモリの合計がRAM容量の約3/4未満である限り、スワップスペースがまったくなくても問題なく動作します。 .... RAMが4GB以下のシステム[持っていることが推奨されます]最小2GBのスワップ領域。

_/proc/sys/vm_設定を単純なCentOS 5.3インストールと比較します。スワップファイルを追加します。 swappinessをラチェットダウンして、もう生きていないか確認してください。

8
pilcrow

顧客/ユーザーがclone()システムコールに干渉しているカーネルモジュールまたはドライバーをロードしている(疑わしいセキュリティ強化、LIDSのようなものですが、もっとわかりにくい)のではないかと疑っています。 fork()/clone()が動作するために必要なカーネルデータ構造の一部(プロセステーブル、ページテーブル、ファイル記述子テーブルなど)。

fork(2) manページの関連部分は次のとおりです。

エラー
 EAGAIN fork()は、親のページテーブルをコピーし、
子にタスク構造を割り当てるのに十分なメモリを割り当てることができません。
 
 EAGAIN呼び出し元のRLIMIT_NPROCリソース制限が発生したため、新しいプロセスを作成できませんでした。 
がこの制限を超えるには、プロセスにCAP_SYS_ADMINまたはCAP_SYS_RESOURCE機能のいずれかが必要です。
 
 ENOMEM fork()は、メモリが不足しているため、必要なカーネル構造の割り当てに失敗しました。 ____。]

標準の汎用カーネルを起動した後、最小限のモジュールとドライバーのセット(アプリケーション/スクリプトを実行するために最低限必要)のみを起動した後、ユーザーにこれを試してもらうことをお勧めします。そこから、それがその構成で機能すると仮定すると、彼らはそれと問題を示す構成との間でバイナリ検索を実行できます。これは、sysadminの標準的なトラブルシューティング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()システムコールは、リソース制限違反(RLIMIT_NPROC)を引き起こす場合にEAGAINを返す必要があります...しかし、EAGAINが返されるかどうかはわかりません他のRLIMIT *違反による。いずれにしても、ターゲット/ホストに何らかの奇妙なVormetricまたはその他のセキュリティ設定がある場合(または、プロセスが何らかの奇妙なSELinuxポリシーで実行されている場合でも)、この-ENOMEMエラーが発生している可能性があります。

普通のLinux/UNIXの普通の問題ではないでしょう。そこには非標準的なものがあります。

5
Jim Dennis

簡単に修正するには、

echo 1 > /proc/sys/vm/overcommit_memory

システムに十分なメモリがあることが確実な場合。 Linux over commit heuristic を参照してください。

5
serv-inc

あなたが使用してみました:

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

これでまったく同じ問題が解決したと思った。しかし、その後、私のプロセスはスポーンに失敗する代わりに殺されてしまいました。これはさらに悪いことです。

いくつかのテストの後、これはpythonの古いバージョンでのみ発生することがわかりました。2.7.2ではなく2.6.5で発生します

私の検索は私をここに導いた python-close_fds-issue が、closed_fdsの設定を解除しても問題は解決しなかった。まだ読む価値があります。

pythonに注目するだけでファイル記述子がリークしていることがわかりました。

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

あなたのように、コマンドの出力をキャプチャし、OOMエラーを回避したいのですが、バグの少ないバージョンのPythonを使用するのが唯一の方法のようです。理想的ではない...

2
totaam

munmap(0xb7d28000、4096)= 0
write(2、 "OSError"、7)= 7

私はこのように見えるずさんなコードを見てきました:

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

pythonコードでこれが起こっているかどうかを確認する必要があります。Errnoは、進行中のシステムコールが失敗した場合にのみ有効です。

追加するために編集:

このプロセスがどれだけ長く続くかは言わない。メモリの可能な消費者

  • 分岐したプロセス
  • 未使用のデータ構造
  • 共有ライブラリ
  • メモリマップファイル
0
codeDr